From c6b1a3430bfb70523133ed871c64e69aaeb7aaa4 Mon Sep 17 00:00:00 2001 From: DrKLO Date: Thu, 9 Oct 2014 00:22:22 +0400 Subject: [PATCH 01/18] Updated database structure, updated sqlite (don't use this source code, it may be changed) --- TMessagesProj/jni/sqlite/sqlite3.c | 8281 +++++++++++------ TMessagesProj/jni/sqlite/sqlite3.h | 244 +- .../libs/armeabi-v7a/libtmessages.so | Bin 1028848 -> 1032992 bytes TMessagesProj/libs/armeabi/libtmessages.so | Bin 946908 -> 951052 bytes TMessagesProj/libs/x86/libtmessages.so | Bin 1603780 -> 1612020 bytes .../telegram/android/ContactsController.java | 38 +- .../telegram/android/MessagesController.java | 54 +- .../org/telegram/android/MessagesStorage.java | 483 +- .../org/telegram/android/NativeLoader.java | 6 +- .../java/org/telegram/messenger/TLRPC.java | 35 + .../java/org/telegram/ui/ChatActivity.java | 20 +- .../java/org/telegram/ui/PhotoViewer.java | 2 +- .../src/main/res/anim/decelerate_cubic.xml | 3 + TMessagesProj/src/main/res/anim/scale_in.xml | 36 +- TMessagesProj/src/main/res/anim/scale_out.xml | 40 +- .../src/main/res/drawable-hdpi/burn.png | Bin 0 -> 2824 bytes .../src/main/res/drawable-ldpi/burn.png | Bin 0 -> 1803 bytes .../src/main/res/drawable-mdpi/burn.png | Bin 0 -> 2175 bytes .../src/main/res/drawable-xhdpi/burn.png | Bin 0 -> 3645 bytes .../src/main/res/drawable-xxhdpi/burn.png | Bin 0 -> 5245 bytes 20 files changed, 5921 insertions(+), 3321 deletions(-) create mode 100644 TMessagesProj/src/main/res/anim/decelerate_cubic.xml create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/burn.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/burn.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/burn.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/burn.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/burn.png diff --git a/TMessagesProj/jni/sqlite/sqlite3.c b/TMessagesProj/jni/sqlite/sqlite3.c index 7c6d3e28..c1278e65 100644 --- a/TMessagesProj/jni/sqlite/sqlite3.c +++ b/TMessagesProj/jni/sqlite/sqlite3.c @@ -1,6 +1,6 @@ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.8.4.1. By combining all the individual C code files into this +** version 3.8.6. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements @@ -222,9 +222,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.8.4.1" -#define SQLITE_VERSION_NUMBER 3008004 -#define SQLITE_SOURCE_ID "2014-03-11 15:27:36 018d317b1257ce68a92908b05c9c7cf1494050d0" +#define SQLITE_VERSION "3.8.6" +#define SQLITE_VERSION_NUMBER 3008006 +#define SQLITE_SOURCE_ID "2014-08-15 11:46:33 9491ba7d738528f168657adb43a198238abde19e" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -384,7 +384,7 @@ typedef sqlite_uint64 sqlite3_uint64; ** ** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors ** for the [sqlite3] object. -** ^Calls to sqlite3_close() and sqlite3_close_v2() return SQLITE_OK if +** ^Calls to sqlite3_close() and sqlite3_close_v2() return [SQLITE_OK] if ** the [sqlite3] object is successfully destroyed and all associated ** resources are deallocated. ** @@ -392,7 +392,7 @@ typedef sqlite_uint64 sqlite3_uint64; ** statements or unfinished sqlite3_backup objects then sqlite3_close() ** will leave the database connection open and return [SQLITE_BUSY]. ** ^If sqlite3_close_v2() is called with unfinalized prepared statements -** and unfinished sqlite3_backups, then the database connection becomes +** and/or unfinished sqlite3_backups, then the database connection becomes ** an unusable "zombie" which will automatically be deallocated when the ** last prepared statement is finalized or the last sqlite3_backup is ** finished. The sqlite3_close_v2() interface is intended for use with @@ -405,7 +405,7 @@ typedef sqlite_uint64 sqlite3_uint64; ** with the [sqlite3] object prior to attempting to close the object. ^If ** sqlite3_close_v2() is called on a [database connection] that still has ** outstanding [prepared statements], [BLOB handles], and/or -** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation +** [sqlite3_backup] objects then it returns [SQLITE_OK] and the deallocation ** of resources is deferred until all [prepared statements], [BLOB handles], ** and [sqlite3_backup] objects are also destroyed. ** @@ -501,16 +501,14 @@ SQLITE_API int sqlite3_exec( /* ** CAPI3REF: Result Codes -** KEYWORDS: SQLITE_OK {error code} {error codes} -** KEYWORDS: {result code} {result codes} +** KEYWORDS: {result code definitions} ** ** Many SQLite functions return an integer result code from the set shown ** here in order to indicate success or failure. ** ** New error codes may be added in future versions of SQLite. ** -** See also: [SQLITE_IOERR_READ | extended result codes], -** [sqlite3_vtab_on_conflict()] [SQLITE_ROLLBACK | result codes]. +** See also: [extended result code definitions] */ #define SQLITE_OK 0 /* Successful result */ /* beginning-of-error-codes */ @@ -548,26 +546,19 @@ SQLITE_API int sqlite3_exec( /* ** CAPI3REF: Extended Result Codes -** KEYWORDS: {extended error code} {extended error codes} -** KEYWORDS: {extended result code} {extended result codes} +** KEYWORDS: {extended result code definitions} ** -** In its default configuration, SQLite API routines return one of 26 integer -** [SQLITE_OK | result codes]. However, experience has shown that many of +** In its default configuration, SQLite API routines return one of 30 integer +** [result codes]. However, experience has shown that many of ** these result codes are too coarse-grained. They do not provide as ** much information about problems as programmers might like. In an effort to ** address this, newer versions of SQLite (version 3.3.8 and later) include ** support for additional result codes that provide more detailed information -** about errors. The extended result codes are enabled or disabled +** about errors. These [extended result codes] are enabled or disabled ** on a per database connection basis using the -** [sqlite3_extended_result_codes()] API. -** -** Some of the available extended result codes are listed here. -** One may expect the number of extended result codes will increase -** over time. Software that uses extended result codes should expect -** to see new result codes in future releases of SQLite. -** -** The SQLITE_OK result code will never be extended. It will always -** be exactly zero. +** [sqlite3_extended_result_codes()] API. Or, the extended code for +** the most recent error can be obtained using +** [sqlite3_extended_errcode()]. */ #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) #define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) @@ -675,7 +666,10 @@ SQLITE_API int sqlite3_exec( ** file that were written at the application level might have changed ** and that adjacent bytes, even bytes within the same sector are ** guaranteed to be unchanged. The SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN -** flag indicate that a file cannot be deleted when open. +** flag indicate that a file cannot be deleted when open. The +** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on +** read-only media and cannot be changed even by processes with +** elevated privileges. */ #define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC512 0x00000002 @@ -690,6 +684,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOCAP_SEQUENTIAL 0x00000400 #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800 #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 +#define SQLITE_IOCAP_IMMUTABLE 0x00002000 /* ** CAPI3REF: File Locking Levels @@ -796,7 +791,7 @@ struct sqlite3_file { ** locking strategy (for example to use dot-file locks), to inquire ** about the status of a lock, or to break stale locks. The SQLite ** core reserves all opcodes less than 100 for its own use. -** A [SQLITE_FCNTL_LOCKSTATE | list of opcodes] less than 100 is available. +** A [file control opcodes | list of opcodes] less than 100 is available. ** Applications that define a custom xFileControl method should use opcodes ** greater than 100 to avoid conflicts. VFS implementations should ** return [SQLITE_NOTFOUND] for file control opcodes that they do not @@ -869,6 +864,7 @@ struct sqlite3_io_methods { /* ** CAPI3REF: Standard File Control Opcodes +** KEYWORDS: {file control opcodes} {file control opcode} ** ** These integer constants are opcodes for the xFileControl method ** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()] @@ -1058,6 +1054,12 @@ struct sqlite3_io_methods { ** on whether or not the file has been renamed, moved, or deleted since it ** was first opened. ** +**
  • [[SQLITE_FCNTL_WIN32_SET_HANDLE]] +** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This +** opcode causes the xFileControl method to swap the file handle with the one +** pointed to by the pArg argument. This capability is used during testing +** and only needs to be supported when SQLITE_TEST is defined. +** ** */ #define SQLITE_FCNTL_LOCKSTATE 1 @@ -1081,6 +1083,7 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_HAS_MOVED 20 #define SQLITE_FCNTL_SYNC 21 #define SQLITE_FCNTL_COMMIT_PHASETWO 22 +#define SQLITE_FCNTL_WIN32_SET_HANDLE 23 /* ** CAPI3REF: Mutex Handle @@ -2141,27 +2144,33 @@ SQLITE_API int sqlite3_complete16(const void *sql); /* ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors ** -** ^This routine sets a callback function that might be invoked whenever -** an attempt is made to open a database table that another thread -** or process has locked. +** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X +** that might be invoked with argument P whenever +** an attempt is made to access a database table associated with +** [database connection] D when another thread +** or process has the table locked. +** The sqlite3_busy_handler() interface is used to implement +** [sqlite3_busy_timeout()] and [PRAGMA busy_timeout]. ** -** ^If the busy callback is NULL, then [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED] +** ^If the busy callback is NULL, then [SQLITE_BUSY] ** is returned immediately upon encountering the lock. ^If the busy callback ** is not NULL, then the callback might be invoked with two arguments. ** ** ^The first argument to the busy handler is a copy of the void* pointer which ** is the third argument to sqlite3_busy_handler(). ^The second argument to ** the busy handler callback is the number of times that the busy handler has -** been invoked for this locking event. ^If the +** been invoked for the same locking event. ^If the ** busy callback returns 0, then no additional attempts are made to -** access the database and [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED] is returned. +** access the database and [SQLITE_BUSY] is returned +** to the application. ** ^If the callback returns non-zero, then another attempt -** is made to open the database for reading and the cycle repeats. +** is made to access the database and the cycle repeats. ** ** The presence of a busy handler does not guarantee that it will be invoked ** when there is lock contention. ^If SQLite determines that invoking the busy ** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY] -** or [SQLITE_IOERR_BLOCKED] instead of invoking the busy handler. +** to the application instead of invoking the +** busy handler. ** Consider a scenario where one process is holding a read lock that ** it is trying to promote to a reserved lock and ** a second process is holding a reserved lock that it is trying @@ -2175,28 +2184,15 @@ SQLITE_API int sqlite3_complete16(const void *sql); ** ** ^The default busy callback is NULL. ** -** ^The [SQLITE_BUSY] error is converted to [SQLITE_IOERR_BLOCKED] -** when SQLite is in the middle of a large transaction where all the -** changes will not fit into the in-memory cache. SQLite will -** already hold a RESERVED lock on the database file, but it needs -** to promote this lock to EXCLUSIVE so that it can spill cache -** pages into the database file without harm to concurrent -** readers. ^If it is unable to promote the lock, then the in-memory -** cache will be left in an inconsistent state and so the error -** code is promoted from the relatively benign [SQLITE_BUSY] to -** the more severe [SQLITE_IOERR_BLOCKED]. ^This error code promotion -** forces an automatic rollback of the changes. See the -** -** CorruptionFollowingBusyError wiki page for a discussion of why -** this is important. -** ** ^(There can only be a single busy handler defined for each ** [database connection]. Setting a new busy handler clears any ** previously set handler.)^ ^Note that calling [sqlite3_busy_timeout()] -** will also set or clear the busy handler. +** or evaluating [PRAGMA busy_timeout=N] will change the +** busy handler and thus clear any previously set busy handler. ** ** The busy callback should not take any actions which modify the -** database connection that invoked the busy handler. Any such actions +** database connection that invoked the busy handler. In other words, +** the busy handler is not reentrant. Any such actions ** result in undefined behavior. ** ** A busy handler must not close the database connection @@ -2212,7 +2208,7 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); ** will sleep multiple times until at least "ms" milliseconds of sleeping ** have accumulated. ^After at least "ms" milliseconds of sleeping, ** the handler returns 0 which causes [sqlite3_step()] to return -** [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED]. +** [SQLITE_BUSY]. ** ** ^Calling this routine with an argument less than or equal to zero ** turns off all busy handlers. @@ -2221,6 +2217,8 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); ** [database connection] any any given moment. If another busy handler ** was defined (using [sqlite3_busy_handler()]) prior to calling ** this routine, that other busy handler is cleared.)^ +** +** See also: [PRAGMA busy_timeout] */ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); @@ -2622,8 +2620,8 @@ SQLITE_API int sqlite3_set_authorizer( ** [sqlite3_set_authorizer | authorizer documentation] for additional ** information. ** -** Note that SQLITE_IGNORE is also used as a [SQLITE_ROLLBACK | return code] -** from the [sqlite3_vtab_on_conflict()] interface. +** Note that SQLITE_IGNORE is also used as a [conflict resolution mode] +** returned from the [sqlite3_vtab_on_conflict()] interface. */ #define SQLITE_DENY 1 /* Abort the SQL statement with an error */ #define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ @@ -2894,6 +2892,30 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** ^If sqlite3_open_v2() is used and the "cache" parameter is present in ** a URI filename, its value overrides any behavior requested by setting ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. +** +**
  • psow: ^The psow parameter may be "true" (or "on" or "yes" or +** "1") or "false" (or "off" or "no" or "0") to indicate that the +** [powersafe overwrite] property does or does not apply to the +** storage media on which the database file resides. ^The psow query +** parameter only works for the built-in unix and Windows VFSes. +** +**
  • nolock: ^The nolock parameter is a boolean query parameter +** which if set disables file locking in rollback journal modes. This +** is useful for accessing a database on a filesystem that does not +** support locking. Caution: Database corruption might result if two +** or more processes write to the same database and any one of those +** processes uses nolock=1. +** +**
  • immutable: ^The immutable parameter is a boolean query +** parameter that indicates that the database file is stored on +** read-only media. ^When immutable is set, SQLite assumes that the +** database file cannot be changed, even by a process with higher +** privilege, and so the database is opened read-only and all locking +** and change detection is disabled. Caution: Setting the immutable +** property on a database file that does in fact change can result +** in incorrect query results and/or [SQLITE_CORRUPT] errors. +** See also: [SQLITE_IOCAP_IMMUTABLE]. +** ** ** ** ^Specifying an unknown parameter in the query component of a URI is not an @@ -2923,8 +2945,9 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** Open file "data.db" in the current directory for read-only access. ** Regardless of whether or not shared-cache mode is enabled by ** default, use a private cache. -** file:/home/fred/data.db?vfs=unix-nolock -** Open file "/home/fred/data.db". Use the special VFS "unix-nolock". +** file:/home/fred/data.db?vfs=unix-dotfile +** Open file "/home/fred/data.db". Use the special VFS "unix-dotfile" +** that uses dot-files in place of posix advisory locking. ** file:data.db?mode=readonly ** An error. "readonly" is not a valid option for the "mode" parameter. ** @@ -4785,6 +4808,13 @@ SQLITE_API int sqlite3_sleep(int); ** is a NULL pointer, then SQLite performs a search for an appropriate ** temporary file directory. ** +** Applications are strongly discouraged from using this global variable. +** It is required to set a temporary folder on Windows Runtime (WinRT). +** But for all other platforms, it is highly recommended that applications +** neither read nor write this variable. This global variable is a relic +** that exists for backwards compatibility of legacy applications and should +** be avoided in new projects. +** ** It is not safe to read or modify this variable in more than one ** thread at a time. It is not safe to read or modify this variable ** if a [database connection] is being used at the same time in a separate @@ -4803,6 +4833,11 @@ SQLITE_API int sqlite3_sleep(int); ** Hence, if this variable is modified directly, either it should be ** made NULL or made to point to memory obtained from [sqlite3_malloc] ** or else the use of the [temp_store_directory pragma] should be avoided. +** Except when requested by the [temp_store_directory pragma], SQLite +** does not free the memory that sqlite3_temp_directory points to. If +** the application wants that memory to be freed, it must do +** so itself, taking care to only do so after all [database connection] +** objects have been destroyed. ** ** Note to Windows Runtime users: The temporary directory must be set ** prior to calling [sqlite3_open] or [sqlite3_open_v2]. Otherwise, various @@ -5937,10 +5972,12 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*); **
  • SQLITE_MUTEX_RECURSIVE **
  • SQLITE_MUTEX_STATIC_MASTER **
  • SQLITE_MUTEX_STATIC_MEM -**
  • SQLITE_MUTEX_STATIC_MEM2 +**
  • SQLITE_MUTEX_STATIC_OPEN **
  • SQLITE_MUTEX_STATIC_PRNG **
  • SQLITE_MUTEX_STATIC_LRU -**
  • SQLITE_MUTEX_STATIC_LRU2 +**
  • SQLITE_MUTEX_STATIC_PMEM +**
  • SQLITE_MUTEX_STATIC_APP1 +**
  • SQLITE_MUTEX_STATIC_APP2 ** )^ ** ** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) @@ -6144,6 +6181,9 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*); #define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */ #define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */ #define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */ +#define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */ +#define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */ +#define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */ /* ** CAPI3REF: Retrieve the mutex for a database connection @@ -6238,7 +6278,9 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21 -#define SQLITE_TESTCTRL_LAST 21 +#define SQLITE_TESTCTRL_BYTEORDER 22 +#define SQLITE_TESTCTRL_ISINIT 23 +#define SQLITE_TESTCTRL_LAST 23 /* ** CAPI3REF: SQLite Runtime Status @@ -7222,6 +7264,9 @@ SQLITE_API void *sqlite3_wal_hook( ** ^The [wal_autocheckpoint pragma] can be used to invoke this interface ** from SQL. ** +** ^Checkpoints initiated by this mechanism are +** [sqlite3_wal_checkpoint_v2|PASSIVE]. +** ** ^Every new [database connection] defaults to having the auto-checkpoint ** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT] ** pages. The use of this interface @@ -7238,6 +7283,10 @@ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); ** empty string, then a checkpoint is run on all databases of ** connection D. ^If the database connection D is not in ** [WAL | write-ahead log mode] then this interface is a harmless no-op. +** ^The [sqlite3_wal_checkpoint(D,X)] interface initiates a +** [sqlite3_wal_checkpoint_v2|PASSIVE] checkpoint. +** Use the [sqlite3_wal_checkpoint_v2()] interface to get a FULL +** or RESET checkpoint. ** ** ^The [wal_checkpoint pragma] can be used to invoke this interface ** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the @@ -7260,10 +7309,12 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); ** Checkpoint as many frames as possible without waiting for any database ** readers or writers to finish. Sync the db file if all frames in the log ** are checkpointed. This mode is the same as calling -** sqlite3_wal_checkpoint(). The busy-handler callback is never invoked. +** sqlite3_wal_checkpoint(). The [sqlite3_busy_handler|busy-handler callback] +** is never invoked. ** **
    SQLITE_CHECKPOINT_FULL
    -** This mode blocks (calls the busy-handler callback) until there is no +** This mode blocks (it invokes the +** [sqlite3_busy_handler|busy-handler callback]) until there is no ** database writer and all readers are reading from the most recent database ** snapshot. It then checkpoints all frames in the log file and syncs the ** database file. This call blocks database writers while it is running, @@ -7271,7 +7322,8 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); ** **
    SQLITE_CHECKPOINT_RESTART
    ** This mode works the same way as SQLITE_CHECKPOINT_FULL, except after -** checkpointing the log file it blocks (calls the busy-handler callback) +** checkpointing the log file it blocks (calls the +** [sqlite3_busy_handler|busy-handler callback]) ** until all readers are reading from the database file only. This ensures ** that the next client to write to the database file restarts the log file ** from the beginning. This call blocks database writers while it is running, @@ -7409,6 +7461,7 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); /* ** CAPI3REF: Conflict resolution modes +** KEYWORDS: {conflict resolution mode} ** ** These constants are returned by [sqlite3_vtab_on_conflict()] to ** inform a [virtual table] implementation what the [ON CONFLICT] mode @@ -7461,6 +7514,16 @@ extern "C" { #endif typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry; +typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info; + +/* The double-precision datatype used by RTree depends on the +** SQLITE_RTREE_INT_ONLY compile-time option. +*/ +#ifdef SQLITE_RTREE_INT_ONLY + typedef sqlite3_int64 sqlite3_rtree_dbl; +#else + typedef double sqlite3_rtree_dbl; +#endif /* ** Register a geometry callback named zGeom that can be used as part of an @@ -7471,11 +7534,7 @@ typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry; SQLITE_API int sqlite3_rtree_geometry_callback( sqlite3 *db, const char *zGeom, -#ifdef SQLITE_RTREE_INT_ONLY - int (*xGeom)(sqlite3_rtree_geometry*, int n, sqlite3_int64 *a, int *pRes), -#else - int (*xGeom)(sqlite3_rtree_geometry*, int n, double *a, int *pRes), -#endif + int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*), void *pContext ); @@ -7487,11 +7546,60 @@ SQLITE_API int sqlite3_rtree_geometry_callback( struct sqlite3_rtree_geometry { void *pContext; /* Copy of pContext passed to s_r_g_c() */ int nParam; /* Size of array aParam[] */ - double *aParam; /* Parameters passed to SQL geom function */ + sqlite3_rtree_dbl *aParam; /* Parameters passed to SQL geom function */ void *pUser; /* Callback implementation user data */ void (*xDelUser)(void *); /* Called by SQLite to clean up pUser */ }; +/* +** Register a 2nd-generation geometry callback named zScore that can be +** used as part of an R-Tree geometry query as follows: +** +** SELECT ... FROM WHERE MATCH $zQueryFunc(... params ...) +*/ +SQLITE_API int sqlite3_rtree_query_callback( + sqlite3 *db, + const char *zQueryFunc, + int (*xQueryFunc)(sqlite3_rtree_query_info*), + void *pContext, + void (*xDestructor)(void*) +); + + +/* +** A pointer to a structure of the following type is passed as the +** argument to scored geometry callback registered using +** sqlite3_rtree_query_callback(). +** +** Note that the first 5 fields of this structure are identical to +** sqlite3_rtree_geometry. This structure is a subclass of +** sqlite3_rtree_geometry. +*/ +struct sqlite3_rtree_query_info { + void *pContext; /* pContext from when function registered */ + int nParam; /* Number of function parameters */ + sqlite3_rtree_dbl *aParam; /* value of function parameters */ + void *pUser; /* callback can use this, if desired */ + void (*xDelUser)(void*); /* function to free pUser */ + sqlite3_rtree_dbl *aCoord; /* Coordinates of node or entry to check */ + unsigned int *anQueue; /* Number of pending entries in the queue */ + int nCoord; /* Number of coordinates */ + int iLevel; /* Level of current node or entry */ + int mxLevel; /* The largest iLevel value in the tree */ + sqlite3_int64 iRowid; /* Rowid for current entry */ + sqlite3_rtree_dbl rParentScore; /* Score of parent node */ + int eParentWithin; /* Visibility of parent node */ + int eWithin; /* OUT: Visiblity */ + sqlite3_rtree_dbl rScore; /* OUT: Write the score here */ +}; + +/* +** Allowed values for sqlite3_rtree_query.eWithin and .eParentWithin. +*/ +#define NOT_WITHIN 0 /* Object completely outside of query region */ +#define PARTLY_WITHIN 1 /* Object partially overlaps query region */ +#define FULLY_WITHIN 2 /* Object fully contained within query region */ + #if 0 } /* end of the 'extern "C"' block */ @@ -8418,10 +8526,10 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */ ** gives a possible range of values of approximately 1.0e986 to 1e-986. ** But the allowed values are "grainy". Not every value is representable. ** For example, quantities 16 and 17 are both represented by a LogEst -** of 40. However, since LogEst quantatites are suppose to be estimates, +** of 40. However, since LogEst quantaties are suppose to be estimates, ** not exact values, this imprecision is not a problem. ** -** "LogEst" is short for "Logarithimic Estimate". +** "LogEst" is short for "Logarithmic Estimate". ** ** Examples: ** 1 -> 0 20 -> 43 10000 -> 132 @@ -8439,22 +8547,39 @@ typedef INT16_TYPE LogEst; /* ** Macros to determine whether the machine is big or little endian, -** evaluated at runtime. +** and whether or not that determination is run-time or compile-time. +** +** For best performance, an attempt is made to guess at the byte-order +** using C-preprocessor macros. If that is unsuccessful, or if +** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined +** at run-time. */ #ifdef SQLITE_AMALGAMATION SQLITE_PRIVATE const int sqlite3one = 1; #else SQLITE_PRIVATE const int sqlite3one; #endif -#if defined(i386) || defined(__i386__) || defined(_M_IX86)\ - || defined(__x86_64) || defined(__x86_64__) +#if (defined(i386) || defined(__i386__) || defined(_M_IX86) || \ + defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ + defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ + defined(__arm__)) && !defined(SQLITE_RUNTIME_BYTEORDER) +# define SQLITE_BYTEORDER 1234 # define SQLITE_BIGENDIAN 0 # define SQLITE_LITTLEENDIAN 1 # define SQLITE_UTF16NATIVE SQLITE_UTF16LE -#else +#endif +#if (defined(sparc) || defined(__ppc__)) \ + && !defined(SQLITE_RUNTIME_BYTEORDER) +# define SQLITE_BYTEORDER 4321 +# define SQLITE_BIGENDIAN 1 +# define SQLITE_LITTLEENDIAN 0 +# define SQLITE_UTF16NATIVE SQLITE_UTF16BE +#endif +#if !defined(SQLITE_BYTEORDER) +# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */ # define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0) # define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1) -# define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE) +# define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE) #endif /* @@ -8769,7 +8894,9 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( SQLITE_PRIVATE int sqlite3BtreeClose(Btree*); SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int); -SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64); +#if SQLITE_MAX_MMAP_SIZE>0 +SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64); +#endif SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(Btree*,unsigned); SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree*); SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix); @@ -8819,6 +8946,7 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *); SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*); SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, int*); +SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor*); SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree*, int); SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue); @@ -8893,10 +9021,11 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, i SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*); SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*); -SQLITE_PRIVATE void sqlite3BtreeCacheOverflow(BtCursor *); +SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *); SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *); SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBt, int iVersion); SQLITE_PRIVATE void sqlite3BtreeCursorHints(BtCursor *, unsigned int mask); +SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *pBt); #ifndef NDEBUG SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor*); @@ -9136,7 +9265,7 @@ typedef struct VdbeOpList VdbeOpList; #define OP_Checkpoint 11 #define OP_JournalMode 12 #define OP_Vacuum 13 -#define OP_VFilter 14 /* synopsis: iPlan=r[P3] zPlan='P4' */ +#define OP_VFilter 14 /* synopsis: iplan=r[P3] zplan='P4' */ #define OP_VUpdate 15 /* synopsis: data=r[P3@P2] */ #define OP_Goto 16 #define OP_Gosub 17 @@ -9163,7 +9292,7 @@ typedef struct VdbeOpList VdbeOpList; #define OP_MustBeInt 38 #define OP_RealAffinity 39 #define OP_Permutation 40 -#define OP_Compare 41 +#define OP_Compare 41 /* synopsis: r[P1@P3] <-> r[P2@P3] */ #define OP_Jump 42 #define OP_Once 43 #define OP_If 44 @@ -9174,30 +9303,30 @@ typedef struct VdbeOpList VdbeOpList; #define OP_Count 49 /* synopsis: r[P2]=count() */ #define OP_ReadCookie 50 #define OP_SetCookie 51 -#define OP_OpenRead 52 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenWrite 53 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenAutoindex 54 /* synopsis: nColumn=P2 */ -#define OP_OpenEphemeral 55 /* synopsis: nColumn=P2 */ -#define OP_SorterOpen 56 -#define OP_OpenPseudo 57 /* synopsis: P3 columns in r[P2] */ -#define OP_Close 58 -#define OP_SeekLT 59 -#define OP_SeekLE 60 -#define OP_SeekGE 61 -#define OP_SeekGT 62 -#define OP_Seek 63 /* synopsis: intkey=r[P2] */ -#define OP_NoConflict 64 /* synopsis: key=r[P3@P4] */ -#define OP_NotFound 65 /* synopsis: key=r[P3@P4] */ -#define OP_Found 66 /* synopsis: key=r[P3@P4] */ -#define OP_NotExists 67 /* synopsis: intkey=r[P3] */ -#define OP_Sequence 68 /* synopsis: r[P2]=rowid */ -#define OP_NewRowid 69 /* synopsis: r[P2]=rowid */ -#define OP_Insert 70 /* synopsis: intkey=r[P3] data=r[P2] */ +#define OP_ReopenIdx 52 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenRead 53 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenWrite 54 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenAutoindex 55 /* synopsis: nColumn=P2 */ +#define OP_OpenEphemeral 56 /* synopsis: nColumn=P2 */ +#define OP_SorterOpen 57 +#define OP_OpenPseudo 58 /* synopsis: P3 columns in r[P2] */ +#define OP_Close 59 +#define OP_SeekLT 60 /* synopsis: key=r[P3@P4] */ +#define OP_SeekLE 61 /* synopsis: key=r[P3@P4] */ +#define OP_SeekGE 62 /* synopsis: key=r[P3@P4] */ +#define OP_SeekGT 63 /* synopsis: key=r[P3@P4] */ +#define OP_Seek 64 /* synopsis: intkey=r[P2] */ +#define OP_NoConflict 65 /* synopsis: key=r[P3@P4] */ +#define OP_NotFound 66 /* synopsis: key=r[P3@P4] */ +#define OP_Found 67 /* synopsis: key=r[P3@P4] */ +#define OP_NotExists 68 /* synopsis: intkey=r[P3] */ +#define OP_Sequence 69 /* synopsis: r[P2]=cursor[P1].ctr++ */ +#define OP_NewRowid 70 /* synopsis: r[P2]=rowid */ #define OP_Or 71 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ #define OP_And 72 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ -#define OP_InsertInt 73 /* synopsis: intkey=P3 data=r[P2] */ -#define OP_Delete 74 -#define OP_ResetCount 75 +#define OP_Insert 73 /* synopsis: intkey=r[P3] data=r[P2] */ +#define OP_InsertInt 74 /* synopsis: intkey=P3 data=r[P2] */ +#define OP_Delete 75 #define OP_IsNull 76 /* same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ #define OP_NotNull 77 /* same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ #define OP_Ne 78 /* same as TK_NE, synopsis: if r[P1]!=r[P3] goto P2 */ @@ -9206,7 +9335,7 @@ typedef struct VdbeOpList VdbeOpList; #define OP_Le 81 /* same as TK_LE, synopsis: if r[P1]<=r[P3] goto P2 */ #define OP_Lt 82 /* same as TK_LT, synopsis: if r[P1]=r[P3] goto P2 */ -#define OP_SorterCompare 84 /* synopsis: if key(P1)!=rtrim(r[P3],P4) goto P2 */ +#define OP_ResetCount 84 #define OP_BitAnd 85 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ #define OP_BitOr 86 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ #define OP_ShiftLeft 87 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<0 goto P2 */ +#define OP_SorterData 98 /* synopsis: r[P2]=data */ +#define OP_RowKey 99 /* synopsis: r[P2]=key */ +#define OP_RowData 100 /* synopsis: r[P2]=data */ +#define OP_Rowid 101 /* synopsis: r[P2]=rowid */ +#define OP_NullRow 102 +#define OP_Last 103 +#define OP_SorterSort 104 +#define OP_Sort 105 +#define OP_Rewind 106 +#define OP_SorterInsert 107 +#define OP_IdxInsert 108 /* synopsis: key=r[P2] */ +#define OP_IdxDelete 109 /* synopsis: key=r[P2@P3] */ +#define OP_IdxRowid 110 /* synopsis: r[P2]=rowid */ +#define OP_IdxLE 111 /* synopsis: key=r[P3@P4] */ +#define OP_IdxGT 112 /* synopsis: key=r[P3@P4] */ +#define OP_IdxLT 113 /* synopsis: key=r[P3@P4] */ +#define OP_IdxGE 114 /* synopsis: key=r[P3@P4] */ +#define OP_Destroy 115 +#define OP_Clear 116 +#define OP_ResetSorter 117 +#define OP_CreateIndex 118 /* synopsis: r[P2]=root iDb=P1 */ +#define OP_CreateTable 119 /* synopsis: r[P2]=root iDb=P1 */ +#define OP_ParseSchema 120 +#define OP_LoadAnalysis 121 +#define OP_DropTable 122 +#define OP_DropIndex 123 +#define OP_DropTrigger 124 +#define OP_IntegrityCk 125 +#define OP_RowSetAdd 126 /* synopsis: rowset(P1)=r[P2] */ +#define OP_RowSetRead 127 /* synopsis: r[P3]=rowset(P1) */ +#define OP_RowSetTest 128 /* synopsis: if r[P3] in rowset(P1) goto P2 */ +#define OP_Program 129 +#define OP_Param 130 +#define OP_FkCounter 131 /* synopsis: fkctr[P1]+=P2 */ +#define OP_FkIfZero 132 /* synopsis: if fkctr[P1]==0 goto P2 */ #define OP_Real 133 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ -#define OP_IfNeg 134 /* synopsis: if r[P1]<0 goto P2 */ -#define OP_IfZero 135 /* synopsis: r[P1]+=P3, if r[P1]==0 goto P2 */ -#define OP_AggFinal 136 /* synopsis: accum=r[P1] N=P2 */ -#define OP_IncrVacuum 137 -#define OP_Expire 138 -#define OP_TableLock 139 /* synopsis: iDb=P1 root=P2 write=P3 */ -#define OP_VBegin 140 -#define OP_VCreate 141 -#define OP_VDestroy 142 +#define OP_MemMax 134 /* synopsis: r[P1]=max(r[P1],r[P2]) */ +#define OP_IfPos 135 /* synopsis: if r[P1]>0 goto P2 */ +#define OP_IfNeg 136 /* synopsis: r[P1]+=P3, if r[P1]<0 goto P2 */ +#define OP_IfZero 137 /* synopsis: r[P1]+=P3, if r[P1]==0 goto P2 */ +#define OP_AggFinal 138 /* synopsis: accum=r[P1] N=P2 */ +#define OP_IncrVacuum 139 +#define OP_Expire 140 +#define OP_TableLock 141 /* synopsis: iDb=P1 root=P2 write=P3 */ +#define OP_VBegin 142 #define OP_ToText 143 /* same as TK_TO_TEXT */ #define OP_ToBlob 144 /* same as TK_TO_BLOB */ #define OP_ToNumeric 145 /* same as TK_TO_NUMERIC */ #define OP_ToInt 146 /* same as TK_TO_INT */ #define OP_ToReal 147 /* same as TK_TO_REAL */ -#define OP_VOpen 148 -#define OP_VColumn 149 /* synopsis: r[P3]=vcolumn(P2) */ -#define OP_VNext 150 -#define OP_VRename 151 -#define OP_Pagecount 152 -#define OP_MaxPgcnt 153 -#define OP_Init 154 /* synopsis: Start at P2 */ -#define OP_Noop 155 -#define OP_Explain 156 +#define OP_VCreate 148 +#define OP_VDestroy 149 +#define OP_VOpen 150 +#define OP_VColumn 151 /* synopsis: r[P3]=vcolumn(P2) */ +#define OP_VNext 152 +#define OP_VRename 153 +#define OP_Pagecount 154 +#define OP_MaxPgcnt 155 +#define OP_Init 156 /* synopsis: Start at P2 */ +#define OP_Noop 157 +#define OP_Explain 158 /* Properties such as "out2" or "jump" that are specified in @@ -9300,19 +9431,19 @@ typedef struct VdbeOpList VdbeOpList; /* 32 */ 0x00, 0x00, 0x20, 0x00, 0x00, 0x04, 0x05, 0x04,\ /* 40 */ 0x00, 0x00, 0x01, 0x01, 0x05, 0x05, 0x00, 0x00,\ /* 48 */ 0x00, 0x02, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00,\ -/* 56 */ 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x08,\ -/* 64 */ 0x11, 0x11, 0x11, 0x11, 0x02, 0x02, 0x00, 0x4c,\ +/* 56 */ 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\ +/* 64 */ 0x08, 0x11, 0x11, 0x11, 0x11, 0x02, 0x02, 0x4c,\ /* 72 */ 0x4c, 0x00, 0x00, 0x00, 0x05, 0x05, 0x15, 0x15,\ /* 80 */ 0x15, 0x15, 0x15, 0x15, 0x00, 0x4c, 0x4c, 0x4c,\ /* 88 */ 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x00,\ -/* 96 */ 0x24, 0x02, 0x00, 0x00, 0x02, 0x00, 0x01, 0x01,\ -/* 104 */ 0x01, 0x01, 0x08, 0x08, 0x00, 0x02, 0x01, 0x01,\ -/* 112 */ 0x01, 0x01, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00,\ -/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x45, 0x15, 0x01,\ -/* 128 */ 0x02, 0x00, 0x01, 0x08, 0x05, 0x02, 0x05, 0x05,\ -/* 136 */ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,\ -/* 144 */ 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x01, 0x00,\ -/* 152 */ 0x02, 0x02, 0x01, 0x00, 0x00,} +/* 96 */ 0x24, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01,\ +/* 104 */ 0x01, 0x01, 0x01, 0x08, 0x08, 0x00, 0x02, 0x01,\ +/* 112 */ 0x01, 0x01, 0x01, 0x02, 0x00, 0x00, 0x02, 0x02,\ +/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x45,\ +/* 128 */ 0x15, 0x01, 0x02, 0x00, 0x01, 0x02, 0x08, 0x05,\ +/* 136 */ 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04,\ +/* 144 */ 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,\ +/* 152 */ 0x01, 0x00, 0x02, 0x02, 0x01, 0x00, 0x00,} /************** End of opcodes.h *********************************************/ /************** Continuing where we left off in vdbe.h ***********************/ @@ -9367,12 +9498,13 @@ SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe*, int); #ifndef SQLITE_OMIT_TRACE SQLITE_PRIVATE char *sqlite3VdbeExpandSql(Vdbe*, const char*); #endif +SQLITE_PRIVATE int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*); -SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,const UnpackedRecord*,int); +SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*,int); SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **); -typedef int (*RecordCompare)(int,const void*,const UnpackedRecord*,int); +typedef int (*RecordCompare)(int,const void*,UnpackedRecord*,int); SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*); #ifndef SQLITE_OMIT_TRIGGER @@ -9850,83 +9982,71 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void); #define _SQLITE_OS_H_ /* -** Figure out if we are dealing with Unix, Windows, or some other -** operating system. After the following block of preprocess macros, -** all of SQLITE_OS_UNIX, SQLITE_OS_WIN, and SQLITE_OS_OTHER -** will defined to either 1 or 0. One of the four will be 1. The other -** three will be 0. +** Attempt to automatically detect the operating system and setup the +** necessary pre-processor macros for it. +*/ +/************** Include os_setup.h in the middle of os.h *********************/ +/************** Begin file os_setup.h ****************************************/ +/* +** 2013 November 25 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains pre-processor directives related to operating system +** detection and/or setup. +*/ +#ifndef _OS_SETUP_H_ +#define _OS_SETUP_H_ + +/* +** Figure out if we are dealing with Unix, Windows, or some other operating +** system. +** +** After the following block of preprocess macros, all of SQLITE_OS_UNIX, +** SQLITE_OS_WIN, and SQLITE_OS_OTHER will defined to either 1 or 0. One of +** the three will be 1. The other two will be 0. */ #if defined(SQLITE_OS_OTHER) -# if SQLITE_OS_OTHER==1 -# undef SQLITE_OS_UNIX -# define SQLITE_OS_UNIX 0 -# undef SQLITE_OS_WIN -# define SQLITE_OS_WIN 0 -# else -# undef SQLITE_OS_OTHER -# endif +# if SQLITE_OS_OTHER==1 +# undef SQLITE_OS_UNIX +# define SQLITE_OS_UNIX 0 +# undef SQLITE_OS_WIN +# define SQLITE_OS_WIN 0 +# else +# undef SQLITE_OS_OTHER +# endif #endif #if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER) -# define SQLITE_OS_OTHER 0 -# ifndef SQLITE_OS_WIN -# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__) -# define SQLITE_OS_WIN 1 -# define SQLITE_OS_UNIX 0 -# else -# define SQLITE_OS_WIN 0 -# define SQLITE_OS_UNIX 1 +# define SQLITE_OS_OTHER 0 +# ifndef SQLITE_OS_WIN +# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || \ + defined(__MINGW32__) || defined(__BORLANDC__) +# define SQLITE_OS_WIN 1 +# define SQLITE_OS_UNIX 0 +# else +# define SQLITE_OS_WIN 0 +# define SQLITE_OS_UNIX 1 +# endif +# else +# define SQLITE_OS_UNIX 0 # endif -# else -# define SQLITE_OS_UNIX 0 -# endif #else -# ifndef SQLITE_OS_WIN -# define SQLITE_OS_WIN 0 -# endif +# ifndef SQLITE_OS_WIN +# define SQLITE_OS_WIN 0 +# endif #endif -#if SQLITE_OS_WIN -# include -#endif +#endif /* _OS_SETUP_H_ */ -/* -** Determine if we are dealing with Windows NT. -** -** We ought to be able to determine if we are compiling for win98 or winNT -** using the _WIN32_WINNT macro as follows: -** -** #if defined(_WIN32_WINNT) -** # define SQLITE_OS_WINNT 1 -** #else -** # define SQLITE_OS_WINNT 0 -** #endif -** -** However, vs2005 does not set _WIN32_WINNT by default, as it ought to, -** so the above test does not work. We'll just assume that everything is -** winNT unless the programmer explicitly says otherwise by setting -** SQLITE_OS_WINNT to 0. -*/ -#if SQLITE_OS_WIN && !defined(SQLITE_OS_WINNT) -# define SQLITE_OS_WINNT 1 -#endif - -/* -** Determine if we are dealing with WindowsCE - which has a much -** reduced API. -*/ -#if defined(_WIN32_WCE) -# define SQLITE_OS_WINCE 1 -#else -# define SQLITE_OS_WINCE 0 -#endif - -/* -** Determine if we are dealing with WinRT, which provides only a subset of -** the full Win32 API. -*/ -#if !defined(SQLITE_OS_WINRT) -# define SQLITE_OS_WINRT 0 -#endif +/************** End of os_setup.h ********************************************/ +/************** Continuing where we left off in os.h *************************/ /* If the SET_FULLSYNC macro is not defined above, then make it ** a no-op @@ -10230,7 +10350,7 @@ struct Schema { Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */ u8 file_format; /* Schema format version for this file */ u8 enc; /* Text encoding used by this database */ - u16 flags; /* Flags associated with this schema */ + u16 schemaFlags; /* Flags associated with this schema */ int cache_size; /* Number of pages to use in the cache */ }; @@ -10238,10 +10358,10 @@ struct Schema { ** These macros can be used to test, set, or clear bits in the ** Db.pSchema->flags field. */ -#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))==(P)) -#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))!=0) -#define DbSetProperty(D,I,P) (D)->aDb[I].pSchema->flags|=(P) -#define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->flags&=~(P) +#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))==(P)) +#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))!=0) +#define DbSetProperty(D,I,P) (D)->aDb[I].pSchema->schemaFlags|=(P) +#define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->schemaFlags&=~(P) /* ** Allowed values for the DB.pSchema->flags field. @@ -10825,12 +10945,15 @@ struct Table { #ifndef SQLITE_OMIT_CHECK ExprList *pCheck; /* All CHECK constraints */ #endif - tRowcnt nRowEst; /* Estimated rows in table - from sqlite_stat1 table */ + LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */ int tnum; /* Root BTree node for this table (see note above) */ i16 iPKey; /* If not negative, use aCol[iPKey] as the primary key */ i16 nCol; /* Number of columns in this table */ u16 nRef; /* Number of pointers to this Table */ LogEst szTabRow; /* Estimated size of each table row in bytes */ +#ifdef SQLITE_ENABLE_COSTMULT + LogEst costMult; /* Cost multiplier for using this table */ +#endif u8 tabFlags; /* Mask of TF_* values */ u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ #ifndef SQLITE_OMIT_ALTERTABLE @@ -10998,6 +11121,7 @@ struct UnpackedRecord { KeyInfo *pKeyInfo; /* Collation and sort-order information */ u16 nField; /* Number of entries in apMem[] */ i8 default_rc; /* Comparison result if keys are equal */ + u8 isCorrupt; /* Corruption detected by xRecordCompare() */ Mem *aMem; /* Values */ int r1; /* Value to return if (lhs > rhs) */ int r2; /* Value to return if (rhs < lhs) */ @@ -11033,7 +11157,7 @@ struct UnpackedRecord { struct Index { char *zName; /* Name of this index */ i16 *aiColumn; /* Which columns are used by this index. 1st is 0 */ - tRowcnt *aiRowEst; /* From ANALYZE: Est. rows selected by each column */ + LogEst *aiRowLogEst; /* From ANALYZE: Est. rows selected by each column */ Table *pTable; /* The SQL table being indexed */ char *zColAff; /* String defining the affinity of each column */ Index *pNext; /* The next index associated with the same table */ @@ -11047,7 +11171,7 @@ struct Index { u16 nKeyCol; /* Number of columns forming the key */ u16 nColumn; /* Number of columns stored in the index */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ - unsigned autoIndex:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */ + unsigned idxType:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */ unsigned bUnordered:1; /* Use this index for == or IN queries only */ unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */ unsigned isResized:1; /* True if resizeIndexObject() has been called */ @@ -11060,6 +11184,19 @@ struct Index { #endif }; +/* +** Allowed values for Index.idxType +*/ +#define SQLITE_IDXTYPE_APPDEF 0 /* Created using CREATE INDEX */ +#define SQLITE_IDXTYPE_UNIQUE 1 /* Implements a UNIQUE constraint */ +#define SQLITE_IDXTYPE_PRIMARYKEY 2 /* Is the PRIMARY KEY for the table */ + +/* Return true if index X is a PRIMARY KEY index */ +#define IsPrimaryKeyIndex(X) ((X)->idxType==SQLITE_IDXTYPE_PRIMARYKEY) + +/* Return true if index X is a UNIQUE index */ +#define IsUniqueIndex(X) ((X)->onError!=OE_None) + /* ** Each sample stored in the sqlite_stat3 table is represented in memory ** using a structure of this type. See documentation at the top of the @@ -11264,8 +11401,8 @@ struct Expr { #define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */ #define EP_DblQuoted 0x000040 /* token.z was originally in "..." */ #define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */ -#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE opeartor */ - /* unused 0x000200 */ +#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */ +#define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */ #define EP_IntValue 0x000400 /* Integer value contained in u.iValue */ #define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */ #define EP_Skip 0x001000 /* COLLATE, AS, or UNLIKELY */ @@ -11329,7 +11466,6 @@ struct Expr { */ struct ExprList { int nExpr; /* Number of expressions on the list */ - int iECursor; /* VDBE Cursor associated with this ExprList */ struct ExprList_item { /* For each expression in the list */ Expr *pExpr; /* The list of expressions */ char *zName; /* Token associated with this expression */ @@ -11479,6 +11615,8 @@ struct SrcList { #define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ #define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */ #define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */ +#define WHERE_SORTBYGROUP 0x0800 /* Support sqlite3WhereIsSorted() */ +#define WHERE_REOPEN_IDX 0x1000 /* Try to use OP_ReopenIdx */ /* Allowed return values from sqlite3WhereIsDistinct() */ @@ -11553,7 +11691,7 @@ struct Select { u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ u16 selFlags; /* Various SF_* values */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ - int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */ + int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */ u64 nSelectRow; /* Estimated number of result rows */ SrcList *pSrc; /* The FROM clause */ Expr *pWhere; /* The WHERE clause */ @@ -11577,9 +11715,9 @@ struct Select { #define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */ #define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */ #define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */ -#define SF_UseSorter 0x0040 /* Sort using a sorter */ + /* 0x0040 NOT USED */ #define SF_Values 0x0080 /* Synthesized from VALUES clause */ -#define SF_Materialize 0x0100 /* NOT USED */ + /* 0x0100 NOT USED */ #define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */ #define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */ #define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */ @@ -11632,13 +11770,15 @@ struct Select { ** starting with pDest->iSdst. ** ** SRT_Table Store results in temporary table pDest->iSDParm. -** This is like SRT_EphemTab except that the table -** is assumed to already be open. +** SRT_Fifo This is like SRT_EphemTab except that the table +** is assumed to already be open. SRT_Fifo has +** the additional property of being able to ignore +** the ORDER BY clause. ** -** SRT_DistTable Store results in a temporary table pDest->iSDParm. +** SRT_DistFifo Store results in a temporary table pDest->iSDParm. ** But also use temporary table pDest->iSDParm+1 as ** a record of all prior results and ignore any duplicate -** rows. Name means: "Distinct Table". +** rows. Name means: "Distinct Fifo". ** ** SRT_Queue Store results in priority queue pDest->iSDParm (really ** an index). Append a sequence number so that all entries @@ -11652,19 +11792,20 @@ struct Select { #define SRT_Except 2 /* Remove result from a UNION index */ #define SRT_Exists 3 /* Store 1 if the result is not empty */ #define SRT_Discard 4 /* Do not save the results anywhere */ +#define SRT_Fifo 5 /* Store result as data with an automatic rowid */ +#define SRT_DistFifo 6 /* Like SRT_Fifo, but unique results only */ +#define SRT_Queue 7 /* Store result in an queue */ +#define SRT_DistQueue 8 /* Like SRT_Queue, but unique results only */ /* The ORDER BY clause is ignored for all of the above */ -#define IgnorableOrderby(X) ((X->eDest)<=SRT_Discard) +#define IgnorableOrderby(X) ((X->eDest)<=SRT_DistQueue) -#define SRT_Output 5 /* Output each row of result */ -#define SRT_Mem 6 /* Store result in a memory cell */ -#define SRT_Set 7 /* Store results as keys in an index */ -#define SRT_EphemTab 8 /* Create transient tab and store like SRT_Table */ -#define SRT_Coroutine 9 /* Generate a single row of result */ -#define SRT_Table 10 /* Store result as data with an automatic rowid */ -#define SRT_DistTable 11 /* Like SRT_Table, but unique results only */ -#define SRT_Queue 12 /* Store result in an queue */ -#define SRT_DistQueue 13 /* Like SRT_Queue, but unique results only */ +#define SRT_Output 9 /* Output each row of result */ +#define SRT_Mem 10 /* Store result in a memory cell */ +#define SRT_Set 11 /* Store results as keys in an index */ +#define SRT_EphemTab 12 /* Create transient tab and store like SRT_Table */ +#define SRT_Coroutine 13 /* Generate a single row of result */ +#define SRT_Table 14 /* Store result as data with an automatic rowid */ /* ** An instance of this object describes where to put of the results of @@ -11732,9 +11873,19 @@ struct TriggerPrg { ** The yDbMask datatype for the bitmask of all attached databases. */ #if SQLITE_MAX_ATTACHED>30 - typedef sqlite3_uint64 yDbMask; + typedef unsigned char yDbMask[(SQLITE_MAX_ATTACHED+9)/8]; +# define DbMaskTest(M,I) (((M)[(I)/8]&(1<<((I)&7)))!=0) +# define DbMaskZero(M) memset((M),0,sizeof(M)) +# define DbMaskSet(M,I) (M)[(I)/8]|=(1<<((I)&7)) +# define DbMaskAllZero(M) sqlite3DbMaskAllZero(M) +# define DbMaskNonZero(M) (sqlite3DbMaskAllZero(M)==0) #else typedef unsigned int yDbMask; +# define DbMaskTest(M,I) (((M)&(((yDbMask)1)<<(I)))!=0) +# define DbMaskZero(M) (M)=0 +# define DbMaskSet(M,I) (M)|=(((yDbMask)1)<<(I)) +# define DbMaskAllZero(M) (M)==0 +# define DbMaskNonZero(M) (M)!=0 #endif /* @@ -11762,8 +11913,6 @@ struct Parse { u8 checkSchema; /* Causes schema cookie check after an error */ u8 nested; /* Number of nested calls to the parser/code generator */ u8 nTempReg; /* Number of temporary registers in aTempReg[] */ - u8 nColCache; /* Number of entries in aColCache[] */ - u8 iColCache; /* Next entry in aColCache[] to replace */ u8 isMultiWrite; /* True if statement may modify/insert multiple rows */ u8 mayAbort; /* True if statement may throw an ABORT exception */ u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ @@ -12061,11 +12210,10 @@ struct Sqlite3Config { int isMutexInit; /* True after mutexes are initialized */ int isMallocInit; /* True after malloc is initialized */ int isPCacheInit; /* True after malloc is initialized */ - sqlite3_mutex *pInitMutex; /* Mutex used by sqlite3_initialize() */ int nRefInitMutex; /* Number of users of pInitMutex */ + sqlite3_mutex *pInitMutex; /* Mutex used by sqlite3_initialize() */ void (*xLog)(void*,int,const char*); /* Function for logging */ void *pLogArg; /* First argument to xLog() */ - int bLocaltimeFault; /* True to fail localtime() calls */ #ifdef SQLITE_ENABLE_SQLLOG void(*xSqllog)(void*,sqlite3*,const char*, int); void *pSqllogArg; @@ -12077,6 +12225,10 @@ struct Sqlite3Config { void (*xVdbeBranch)(void*,int iSrcLine,u8 eThis,u8 eMx); /* Callback */ void *pVdbeBranchArg; /* 1st argument */ #endif +#ifndef SQLITE_OMIT_BUILTIN_TEST + int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */ +#endif + int bLocaltimeFault; /* True to fail localtime() calls */ }; /* @@ -12378,6 +12530,12 @@ SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*, SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*); SQLITE_PRIVATE int sqlite3CodeOnce(Parse *); +#ifdef SQLITE_OMIT_BUILTIN_TEST +# define sqlite3FaultSim(X) SQLITE_OK +#else +SQLITE_PRIVATE int sqlite3FaultSim(int); +#endif + SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32); SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec*, u32); SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec*, u32); @@ -12389,7 +12547,7 @@ SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int,int*); SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int); SQLITE_PRIVATE void sqlite3RowSetClear(RowSet*); SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet*, i64); -SQLITE_PRIVATE int sqlite3RowSetTest(RowSet*, u8 iBatch, i64); +SQLITE_PRIVATE int sqlite3RowSetTest(RowSet*, int iBatch, i64); SQLITE_PRIVATE int sqlite3RowSetNext(RowSet*, i64*); SQLITE_PRIVATE void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int); @@ -12400,6 +12558,9 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse*,Table*); # define sqlite3ViewGetColumnNames(A,B) 0 #endif +#if SQLITE_MAX_ATTACHED>30 +SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask); +#endif SQLITE_PRIVATE void sqlite3DropTable(Parse*, SrcList*, int, int); SQLITE_PRIVATE void sqlite3CodeDropTable(Parse*, Table*, int, int); SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3*, Table*); @@ -12445,6 +12606,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*); SQLITE_PRIVATE u64 sqlite3WhereOutputRowCount(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo*); +SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo*, int*); @@ -12453,7 +12615,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCachePush(Parse*); -SQLITE_PRIVATE void sqlite3ExprCachePop(Parse*, int); +SQLITE_PRIVATE void sqlite3ExprCachePop(Parse*); SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse*, int, int); SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse*); SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse*, int, int); @@ -12505,6 +12667,7 @@ SQLITE_PRIVATE int sqlite3IsRowid(const char*); SQLITE_PRIVATE void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8); SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*); SQLITE_PRIVATE int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int); +SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse*,int); SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int, u8,u8,int,int*); SQLITE_PRIVATE void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int); @@ -12648,6 +12811,7 @@ SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2); SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr); SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8); +SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char*, i64*); SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...); SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n); SQLITE_PRIVATE u8 sqlite3HexToInt(int h); @@ -12662,7 +12826,7 @@ SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse); SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); -SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, Token*); +SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*); SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*); SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *); @@ -12677,7 +12841,7 @@ SQLITE_PRIVATE void sqlite3FileSuffix3(const char*, char*); #else # define sqlite3FileSuffix3(X,Y) #endif -SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z,int); +SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z,u8); SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8); SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8); @@ -12762,7 +12926,9 @@ SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *); #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 SQLITE_PRIVATE void sqlite3AnalyzeFunctions(void); SQLITE_PRIVATE int sqlite3Stat4ProbeSetValue(Parse*,Index*,UnpackedRecord**,Expr*,u8,int,int*); +SQLITE_PRIVATE int sqlite3Stat4ValueFromExpr(Parse*, Expr*, u8, sqlite3_value**); SQLITE_PRIVATE void sqlite3Stat4ProbeFree(UnpackedRecord*); +SQLITE_PRIVATE int sqlite3Stat4Column(sqlite3*, const void*, int, int, sqlite3_value**); #endif /* @@ -12899,11 +13065,21 @@ SQLITE_PRIVATE void sqlite3EndBenignMalloc(void); #define sqlite3EndBenignMalloc() #endif -#define IN_INDEX_ROWID 1 -#define IN_INDEX_EPH 2 -#define IN_INDEX_INDEX_ASC 3 -#define IN_INDEX_INDEX_DESC 4 -SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, int*); +/* +** Allowed return values from sqlite3FindInIndex() +*/ +#define IN_INDEX_ROWID 1 /* Search the rowid of the table */ +#define IN_INDEX_EPH 2 /* Search an ephemeral b-tree */ +#define IN_INDEX_INDEX_ASC 3 /* Existing index ASCENDING */ +#define IN_INDEX_INDEX_DESC 4 /* Existing index DESCENDING */ +#define IN_INDEX_NOOP 5 /* No table available. Use comparisons */ +/* +** Allowed flags for the 3rd parameter to sqlite3FindInIndex(). +*/ +#define IN_INDEX_NOOP_OK 0x0001 /* OK to return IN_INDEX_NOOP */ +#define IN_INDEX_MEMBERSHIP 0x0002 /* IN operator used for membership test */ +#define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */ +SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, u32, int*); #ifdef SQLITE_ENABLE_ATOMIC_WRITE SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int); @@ -13181,15 +13357,22 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { 0, /* isMutexInit */ 0, /* isMallocInit */ 0, /* isPCacheInit */ - 0, /* pInitMutex */ 0, /* nRefInitMutex */ + 0, /* pInitMutex */ 0, /* xLog */ 0, /* pLogArg */ - 0, /* bLocaltimeFault */ #ifdef SQLITE_ENABLE_SQLLOG 0, /* xSqllog */ - 0 /* pSqllogArg */ + 0, /* pSqllogArg */ #endif +#ifdef SQLITE_VDBE_COVERAGE + 0, /* xVdbeBranch */ + 0, /* pVbeBranchArg */ +#endif +#ifndef SQLITE_OMIT_BUILTIN_TEST + 0, /* xTestCallback */ +#endif + 0 /* bLocaltimeFault */ }; /* @@ -13743,13 +13926,18 @@ struct VdbeCursor { int pseudoTableReg; /* Register holding pseudotable content. */ i16 nField; /* Number of fields in the header */ u16 nHdrParsed; /* Number of header fields parsed so far */ +#ifdef SQLITE_DEBUG + u8 seekOp; /* Most recent seek operation on this cursor */ +#endif i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */ u8 nullRow; /* True if pointing to a row with no data */ u8 rowidIsValid; /* True if lastRowid is valid */ u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ + Bool isEphemeral:1; /* True for an ephemeral table */ Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */ Bool isTable:1; /* True if a table requiring integer keys */ Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */ + Pgno pgnoRoot; /* Root page of the open btree cursor */ sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */ i64 seqCount; /* Sequence counter */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ @@ -14066,9 +14254,8 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe*, int, int); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); -SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(VdbeCursor*,const UnpackedRecord*,int*); +SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(VdbeCursor*,UnpackedRecord*,int*); SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3*, BtCursor *, i64 *); -SQLITE_PRIVATE int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); SQLITE_PRIVATE int sqlite3VdbeExec(Vdbe*); SQLITE_PRIVATE int sqlite3VdbeList(Vdbe*); SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe*); @@ -14112,6 +14299,7 @@ SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *); SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p); SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *); +SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *); SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *); SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *); SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *); @@ -17851,7 +18039,7 @@ static void *memsys5MallocUnsafe(int nByte){ ** block. If not, then split a block of the next larger power of ** two in order to create a new free block of size iLogsize. */ - for(iBin=iLogsize; mem5.aiFreelist[iBin]<0 && iBin<=LOGMAX; iBin++){} + for(iBin=iLogsize; iBin<=LOGMAX && mem5.aiFreelist[iBin]<0; iBin++){} if( iBin>LOGMAX ){ testcase( sqlite3GlobalConfig.xLog!=0 ); sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes", nByte); @@ -18262,7 +18450,7 @@ SQLITE_PRIVATE int sqlite3MutexEnd(void){ */ SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int id){ #ifndef SQLITE_OMIT_AUTOINIT - if( sqlite3_initialize() ) return 0; + if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0; #endif return sqlite3GlobalConfig.mutex.xMutexAlloc(id); } @@ -18443,7 +18631,7 @@ static int debugMutexEnd(void){ return SQLITE_OK; } ** that means that a mutex could not be allocated. */ static sqlite3_mutex *debugMutexAlloc(int id){ - static sqlite3_debug_mutex aStatic[6]; + static sqlite3_debug_mutex aStatic[SQLITE_MUTEX_STATIC_APP3 - 1]; sqlite3_debug_mutex *pNew = 0; switch( id ){ case SQLITE_MUTEX_FAST: @@ -18640,10 +18828,13 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; } **
  • SQLITE_MUTEX_RECURSIVE **
  • SQLITE_MUTEX_STATIC_MASTER **
  • SQLITE_MUTEX_STATIC_MEM -**
  • SQLITE_MUTEX_STATIC_MEM2 +**
  • SQLITE_MUTEX_STATIC_OPEN **
  • SQLITE_MUTEX_STATIC_PRNG **
  • SQLITE_MUTEX_STATIC_LRU **
  • SQLITE_MUTEX_STATIC_PMEM +**
  • SQLITE_MUTEX_STATIC_APP1 +**
  • SQLITE_MUTEX_STATIC_APP2 +**
  • SQLITE_MUTEX_STATIC_APP3 ** ** ** The first two constants cause sqlite3_mutex_alloc() to create @@ -18677,6 +18868,9 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){ SQLITE3_MUTEX_INITIALIZER, SQLITE3_MUTEX_INITIALIZER, SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, SQLITE3_MUTEX_INITIALIZER }; sqlite3_mutex *p; @@ -18907,12 +19101,303 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ ** May you share freely, never taking more than you give. ** ************************************************************************* -** This file contains the C functions that implement mutexes for win32 +** This file contains the C functions that implement mutexes for Win32. */ +#if SQLITE_OS_WIN +/* +** Include code that is common to all os_*.c files +*/ +/************** Include os_common.h in the middle of mutex_w32.c *************/ +/************** Begin file os_common.h ***************************************/ +/* +** 2004 May 22 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains macros and a little bit of code that is common to +** all of the platform-specific files (os_*.c) and is #included into those +** files. +** +** This file should be #included by the os_*.c files only. It is not a +** general purpose header file. +*/ +#ifndef _OS_COMMON_H_ +#define _OS_COMMON_H_ + +/* +** At least two bugs have slipped in because we changed the MEMORY_DEBUG +** macro to SQLITE_DEBUG and some older makefiles have not yet made the +** switch. The following code should catch this problem at compile-time. +*/ +#ifdef MEMORY_DEBUG +# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." +#endif + +#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) +# ifndef SQLITE_DEBUG_OS_TRACE +# define SQLITE_DEBUG_OS_TRACE 0 +# endif + int sqlite3OSTrace = SQLITE_DEBUG_OS_TRACE; +# define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X +#else +# define OSTRACE(X) +#endif + +/* +** Macros for performance tracing. Normally turned off. Only works +** on i486 hardware. +*/ +#ifdef SQLITE_PERFORMANCE_TRACE + +/* +** hwtime.h contains inline assembler code for implementing +** high-performance timing routines. +*/ +/************** Include hwtime.h in the middle of os_common.h ****************/ +/************** Begin file hwtime.h ******************************************/ +/* +** 2008 May 27 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains inline asm code for retrieving "high-performance" +** counters for x86 class CPUs. +*/ +#ifndef _HWTIME_H_ +#define _HWTIME_H_ + +/* +** The following routine only works on pentium-class (or newer) processors. +** It uses the RDTSC opcode to read the cycle count value out of the +** processor and returns that value. This can be used for high-res +** profiling. +*/ +#if (defined(__GNUC__) || defined(_MSC_VER)) && \ + (defined(i386) || defined(__i386__) || defined(_M_IX86)) + + #if defined(__GNUC__) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned int lo, hi; + __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); + return (sqlite_uint64)hi << 32 | lo; + } + + #elif defined(_MSC_VER) + + __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ + __asm { + rdtsc + ret ; return value at EDX:EAX + } + } + + #endif + +#elif (defined(__GNUC__) && defined(__x86_64__)) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned long val; + __asm__ __volatile__ ("rdtsc" : "=A" (val)); + return val; + } + +#elif (defined(__GNUC__) && defined(__ppc__)) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned long long retval; + unsigned long junk; + __asm__ __volatile__ ("\n\ + 1: mftbu %1\n\ + mftb %L0\n\ + mftbu %0\n\ + cmpw %0,%1\n\ + bne 1b" + : "=r" (retval), "=r" (junk)); + return retval; + } + +#else + + #error Need implementation of sqlite3Hwtime() for your platform. + + /* + ** To compile without implementing sqlite3Hwtime() for your platform, + ** you can remove the above #error and use the following + ** stub function. You will lose timing support for many + ** of the debugging and testing utilities, but it should at + ** least compile and run. + */ +SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } + +#endif + +#endif /* !defined(_HWTIME_H_) */ + +/************** End of hwtime.h **********************************************/ +/************** Continuing where we left off in os_common.h ******************/ + +static sqlite_uint64 g_start; +static sqlite_uint64 g_elapsed; +#define TIMER_START g_start=sqlite3Hwtime() +#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start +#define TIMER_ELAPSED g_elapsed +#else +#define TIMER_START +#define TIMER_END +#define TIMER_ELAPSED ((sqlite_uint64)0) +#endif + +/* +** If we compile with the SQLITE_TEST macro set, then the following block +** of code will give us the ability to simulate a disk I/O error. This +** is used for testing the I/O recovery logic. +*/ +#ifdef SQLITE_TEST +SQLITE_API int sqlite3_io_error_hit = 0; /* Total number of I/O Errors */ +SQLITE_API int sqlite3_io_error_hardhit = 0; /* Number of non-benign errors */ +SQLITE_API int sqlite3_io_error_pending = 0; /* Count down to first I/O error */ +SQLITE_API int sqlite3_io_error_persist = 0; /* True if I/O errors persist */ +SQLITE_API int sqlite3_io_error_benign = 0; /* True if errors are benign */ +SQLITE_API int sqlite3_diskfull_pending = 0; +SQLITE_API int sqlite3_diskfull = 0; +#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X) +#define SimulateIOError(CODE) \ + if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \ + || sqlite3_io_error_pending-- == 1 ) \ + { local_ioerr(); CODE; } +static void local_ioerr(){ + IOTRACE(("IOERR\n")); + sqlite3_io_error_hit++; + if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++; +} +#define SimulateDiskfullError(CODE) \ + if( sqlite3_diskfull_pending ){ \ + if( sqlite3_diskfull_pending == 1 ){ \ + local_ioerr(); \ + sqlite3_diskfull = 1; \ + sqlite3_io_error_hit = 1; \ + CODE; \ + }else{ \ + sqlite3_diskfull_pending--; \ + } \ + } +#else +#define SimulateIOErrorBenign(X) +#define SimulateIOError(A) +#define SimulateDiskfullError(A) +#endif + +/* +** When testing, keep a count of the number of open files. +*/ +#ifdef SQLITE_TEST +SQLITE_API int sqlite3_open_file_count = 0; +#define OpenCounter(X) sqlite3_open_file_count+=(X) +#else +#define OpenCounter(X) +#endif + +#endif /* !defined(_OS_COMMON_H_) */ + +/************** End of os_common.h *******************************************/ +/************** Continuing where we left off in mutex_w32.c ******************/ + +/* +** Include the header file for the Windows VFS. +*/ +/************** Include os_win.h in the middle of mutex_w32.c ****************/ +/************** Begin file os_win.h ******************************************/ +/* +** 2013 November 25 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains code that is specific to Windows. +*/ +#ifndef _OS_WIN_H_ +#define _OS_WIN_H_ + +/* +** Include the primary Windows SDK header file. +*/ +#include "windows.h" + +#ifdef __CYGWIN__ +# include +# include /* amalgamator: dontcache */ +#endif + +/* +** Determine if we are dealing with Windows NT. +** +** We ought to be able to determine if we are compiling for Windows 9x or +** Windows NT using the _WIN32_WINNT macro as follows: +** +** #if defined(_WIN32_WINNT) +** # define SQLITE_OS_WINNT 1 +** #else +** # define SQLITE_OS_WINNT 0 +** #endif +** +** However, Visual Studio 2005 does not set _WIN32_WINNT by default, as +** it ought to, so the above test does not work. We'll just assume that +** everything is Windows NT unless the programmer explicitly says otherwise +** by setting SQLITE_OS_WINNT to 0. +*/ +#if SQLITE_OS_WIN && !defined(SQLITE_OS_WINNT) +# define SQLITE_OS_WINNT 1 +#endif + +/* +** Determine if we are dealing with Windows CE - which has a much reduced +** API. +*/ +#if defined(_WIN32_WCE) +# define SQLITE_OS_WINCE 1 +#else +# define SQLITE_OS_WINCE 0 +#endif + +/* +** Determine if we are dealing with WinRT, which provides only a subset of +** the full Win32 API. +*/ +#if !defined(SQLITE_OS_WINRT) +# define SQLITE_OS_WINRT 0 +#endif + +#endif /* _OS_WIN_H_ */ + +/************** End of os_win.h **********************************************/ +/************** Continuing where we left off in mutex_w32.c ******************/ +#endif + /* ** The code in this file is only used if we are compiling multithreaded -** on a win32 system. +** on a Win32 system. */ #ifdef SQLITE_MUTEX_W32 @@ -18925,48 +19410,22 @@ struct sqlite3_mutex { #ifdef SQLITE_DEBUG volatile int nRef; /* Number of enterances */ volatile DWORD owner; /* Thread holding this mutex */ - int trace; /* True to trace changes */ + volatile int trace; /* True to trace changes */ #endif }; -#define SQLITE_W32_MUTEX_INITIALIZER { 0 } -#ifdef SQLITE_DEBUG -#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, 0L, (DWORD)0, 0 } -#else -#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0 } -#endif /* -** Return true (non-zero) if we are running under WinNT, Win2K, WinXP, -** or WinCE. Return false (zero) for Win95, Win98, or WinME. -** -** Here is an interesting observation: Win95, Win98, and WinME lack -** the LockFileEx() API. But we can still statically link against that -** API as long as we don't call it win running Win95/98/ME. A call to -** this routine is used to determine if the host is Win95/98/ME or -** WinNT/2K/XP so that we will know whether or not we can safely call -** the LockFileEx() API. -** -** mutexIsNT() is only used for the TryEnterCriticalSection() API call, -** which is only available if your application was compiled with -** _WIN32_WINNT defined to a value >= 0x0400. Currently, the only -** call to TryEnterCriticalSection() is #ifdef'ed out, so #ifdef -** this out as well. +** These are the initializer values used when declaring a "static" mutex +** on Win32. It should be noted that all mutexes require initialization +** on the Win32 platform. */ -#if 0 -#if SQLITE_OS_WINCE || SQLITE_OS_WINRT -# define mutexIsNT() (1) +#define SQLITE_W32_MUTEX_INITIALIZER { 0 } + +#ifdef SQLITE_DEBUG +#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, \ + 0L, (DWORD)0, 0 } #else - static int mutexIsNT(void){ - static int osType = 0; - if( osType==0 ){ - OSVERSIONINFO sInfo; - sInfo.dwOSVersionInfoSize = sizeof(sInfo); - GetVersionEx(&sInfo); - osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; - } - return osType==2; - } -#endif /* SQLITE_OS_WINCE || SQLITE_OS_WINRT */ +#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0 } #endif #ifdef SQLITE_DEBUG @@ -18977,20 +19436,24 @@ struct sqlite3_mutex { static int winMutexHeld(sqlite3_mutex *p){ return p->nRef!=0 && p->owner==GetCurrentThreadId(); } + static int winMutexNotheld2(sqlite3_mutex *p, DWORD tid){ return p->nRef==0 || p->owner!=tid; } + static int winMutexNotheld(sqlite3_mutex *p){ - DWORD tid = GetCurrentThreadId(); + DWORD tid = GetCurrentThreadId(); return winMutexNotheld2(p, tid); } #endif - /* ** Initialize and deinitialize the mutex subsystem. */ -static sqlite3_mutex winMutex_staticMutexes[6] = { +static sqlite3_mutex winMutex_staticMutexes[] = { + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, SQLITE3_MUTEX_INITIALIZER, SQLITE3_MUTEX_INITIALIZER, SQLITE3_MUTEX_INITIALIZER, @@ -18998,17 +19461,20 @@ static sqlite3_mutex winMutex_staticMutexes[6] = { SQLITE3_MUTEX_INITIALIZER, SQLITE3_MUTEX_INITIALIZER }; -static int winMutex_isInit = 0; -/* As winMutexInit() and winMutexEnd() are called as part -** of the sqlite3_initialize and sqlite3_shutdown() -** processing, the "interlocked" magic is probably not -** strictly necessary. -*/ -static LONG winMutex_lock = 0; +static int winMutex_isInit = 0; +static int winMutex_isNt = -1; /* <0 means "need to query" */ + +/* As the winMutexInit() and winMutexEnd() functions are called as part +** of the sqlite3_initialize() and sqlite3_shutdown() processing, the +** "interlocked" magic used here is probably not strictly necessary. +*/ +static LONG volatile winMutex_lock = 0; + +SQLITE_API int sqlite3_win32_is_nt(void); /* os_win.c */ SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */ -static int winMutexInit(void){ +static int winMutexInit(void){ /* The first to increment to 1 does actual initialization */ if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){ int i; @@ -19021,16 +19487,17 @@ static int winMutexInit(void){ } winMutex_isInit = 1; }else{ - /* Someone else is in the process of initing the static mutexes */ + /* Another thread is (in the process of) initializing the static + ** mutexes */ while( !winMutex_isInit ){ sqlite3_win32_sleep(1); } } - return SQLITE_OK; + return SQLITE_OK; } -static int winMutexEnd(void){ - /* The first to decrement to 0 does actual shutdown +static int winMutexEnd(void){ + /* The first to decrement to 0 does actual shutdown ** (which should be the last to shutdown.) */ if( InterlockedCompareExchange(&winMutex_lock, 0, 1)==1 ){ if( winMutex_isInit==1 ){ @@ -19041,7 +19508,7 @@ static int winMutexEnd(void){ winMutex_isInit = 0; } } - return SQLITE_OK; + return SQLITE_OK; } /* @@ -19056,10 +19523,13 @@ static int winMutexEnd(void){ **
  • SQLITE_MUTEX_RECURSIVE **
  • SQLITE_MUTEX_STATIC_MASTER **
  • SQLITE_MUTEX_STATIC_MEM -**
  • SQLITE_MUTEX_STATIC_MEM2 +**
  • SQLITE_MUTEX_STATIC_OPEN **
  • SQLITE_MUTEX_STATIC_PRNG **
  • SQLITE_MUTEX_STATIC_LRU **
  • SQLITE_MUTEX_STATIC_PMEM +**
  • SQLITE_MUTEX_STATIC_APP1 +**
  • SQLITE_MUTEX_STATIC_APP2 +**
  • SQLITE_MUTEX_STATIC_APP3 ** ** ** The first two constants cause sqlite3_mutex_alloc() to create @@ -19082,7 +19552,7 @@ static int winMutexEnd(void){ ** ** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() -** returns a different mutex on every call. But for the static +** returns a different mutex on every call. But for the static ** mutex types, the same mutex is returned on every call that has ** the same type number. */ @@ -19093,9 +19563,12 @@ static sqlite3_mutex *winMutexAlloc(int iType){ case SQLITE_MUTEX_FAST: case SQLITE_MUTEX_RECURSIVE: { p = sqlite3MallocZero( sizeof(*p) ); - if( p ){ + if( p ){ #ifdef SQLITE_DEBUG p->id = iType; +#ifdef SQLITE_WIN32_MUTEX_TRACE_DYNAMIC + p->trace = 1; +#endif #endif #if SQLITE_OS_WINRT InitializeCriticalSectionEx(&p->mutex, 0, 0); @@ -19106,12 +19579,15 @@ static sqlite3_mutex *winMutexAlloc(int iType){ break; } default: { - assert( winMutex_isInit==1 ); assert( iType-2 >= 0 ); assert( iType-2 < ArraySize(winMutex_staticMutexes) ); + assert( winMutex_isInit==1 ); p = &winMutex_staticMutexes[iType-2]; #ifdef SQLITE_DEBUG p->id = iType; +#ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC + p->trace = 1; +#endif #endif break; } @@ -19127,8 +19603,11 @@ static sqlite3_mutex *winMutexAlloc(int iType){ */ static void winMutexFree(sqlite3_mutex *p){ assert( p ); +#ifdef SQLITE_DEBUG assert( p->nRef==0 && p->owner==0 ); assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ); +#endif + assert( winMutex_isInit==1 ); DeleteCriticalSection(&p->mutex); sqlite3_free(p); } @@ -19145,30 +19624,39 @@ static void winMutexFree(sqlite3_mutex *p){ ** more than once, the behavior is undefined. */ static void winMutexEnter(sqlite3_mutex *p){ -#ifdef SQLITE_DEBUG - DWORD tid = GetCurrentThreadId(); - assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) ); +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) + DWORD tid = GetCurrentThreadId(); #endif +#ifdef SQLITE_DEBUG + assert( p ); + assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) ); +#else + assert( p ); +#endif + assert( winMutex_isInit==1 ); EnterCriticalSection(&p->mutex); #ifdef SQLITE_DEBUG assert( p->nRef>0 || p->owner==0 ); - p->owner = tid; + p->owner = tid; p->nRef++; if( p->trace ){ - printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); + OSTRACE(("ENTER-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n", + tid, p, p->trace, p->nRef)); } #endif } + static int winMutexTry(sqlite3_mutex *p){ -#ifndef NDEBUG - DWORD tid = GetCurrentThreadId(); +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) + DWORD tid = GetCurrentThreadId(); #endif int rc = SQLITE_BUSY; + assert( p ); assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) ); /* ** The sqlite3_mutex_try() routine is very rarely used, and when it ** is used it is merely an optimization. So it is OK for it to always - ** fail. + ** fail. ** ** The TryEnterCriticalSection() interface is only available on WinNT. ** And some windows compilers complain if you try to use it without @@ -19176,18 +19664,27 @@ static int winMutexTry(sqlite3_mutex *p){ ** For that reason, we will omit this optimization for now. See ** ticket #2685. */ -#if 0 - if( mutexIsNT() && TryEnterCriticalSection(&p->mutex) ){ +#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0400 + assert( winMutex_isInit==1 ); + assert( winMutex_isNt>=-1 && winMutex_isNt<=1 ); + if( winMutex_isNt<0 ){ + winMutex_isNt = sqlite3_win32_is_nt(); + } + assert( winMutex_isNt==0 || winMutex_isNt==1 ); + if( winMutex_isNt && TryEnterCriticalSection(&p->mutex) ){ +#ifdef SQLITE_DEBUG p->owner = tid; p->nRef++; +#endif rc = SQLITE_OK; } #else UNUSED_PARAMETER(p); #endif #ifdef SQLITE_DEBUG - if( rc==SQLITE_OK && p->trace ){ - printf("try mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); + if( p->trace ){ + OSTRACE(("TRY-MUTEX tid=%lu, mutex=%p (%d), owner=%lu, nRef=%d, rc=%s\n", + tid, p, p->trace, p->owner, p->nRef, sqlite3ErrName(rc))); } #endif return rc; @@ -19200,18 +19697,23 @@ static int winMutexTry(sqlite3_mutex *p){ ** is not currently allocated. SQLite will never do either. */ static void winMutexLeave(sqlite3_mutex *p){ -#ifndef NDEBUG +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) DWORD tid = GetCurrentThreadId(); +#endif + assert( p ); +#ifdef SQLITE_DEBUG assert( p->nRef>0 ); assert( p->owner==tid ); p->nRef--; if( p->nRef==0 ) p->owner = 0; assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE ); #endif + assert( winMutex_isInit==1 ); LeaveCriticalSection(&p->mutex); #ifdef SQLITE_DEBUG if( p->trace ){ - printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); + OSTRACE(("LEAVE-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n", + tid, p, p->trace, p->nRef)); } #endif } @@ -19233,9 +19735,9 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ 0 #endif }; - return &sMutex; } + #endif /* SQLITE_MUTEX_W32 */ /************** End of mutex_w32.c *******************************************/ @@ -20161,20 +20663,6 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){ } #endif /* SQLITE_OMIT_FLOATING_POINT */ -/* -** Append N space characters to the given string buffer. -*/ -SQLITE_PRIVATE void sqlite3AppendSpace(StrAccum *pAccum, int N){ - static const char zSpaces[] = " "; - while( N>=(int)sizeof(zSpaces)-1 ){ - sqlite3StrAccumAppend(pAccum, zSpaces, sizeof(zSpaces)-1); - N -= sizeof(zSpaces)-1; - } - if( N>0 ){ - sqlite3StrAccumAppend(pAccum, zSpaces, N); - } -} - /* ** Set the StrAccum object to an error mode. */ @@ -20264,11 +20752,9 @@ SQLITE_PRIVATE void sqlite3VXPrintf( } for(; (c=(*fmt))!=0; ++fmt){ if( c!='%' ){ - int amt; bufpt = (char *)fmt; - amt = 1; - while( (c=(*++fmt))!='%' && c!=0 ) amt++; - sqlite3StrAccumAppend(pAccum, bufpt, amt); + while( (c=(*++fmt))!='%' && c!=0 ){}; + sqlite3StrAccumAppend(pAccum, bufpt, (int)(fmt - bufpt)); if( c==0 ) break; } if( (c=(*++fmt))==0 ){ @@ -20449,10 +20935,8 @@ SQLITE_PRIVATE void sqlite3VXPrintf( *(--bufpt) = zOrd[x*2]; } { - register const char *cset; /* Use registers for speed */ - register int base; - cset = &aDigits[infop->charset]; - base = infop->base; + const char *cset = &aDigits[infop->charset]; + u8 base = infop->base; do{ /* Convert to ascii */ *(--bufpt) = cset[longvalue%base]; longvalue = longvalue/base; @@ -20756,29 +21240,90 @@ SQLITE_PRIVATE void sqlite3VXPrintf( ** "length" characters long. The field width is "width". Do ** the output. */ - if( !flag_leftjustify ){ - register int nspace; - nspace = width-length; - if( nspace>0 ){ - sqlite3AppendSpace(pAccum, nspace); - } - } - if( length>0 ){ - sqlite3StrAccumAppend(pAccum, bufpt, length); - } - if( flag_leftjustify ){ - register int nspace; - nspace = width-length; - if( nspace>0 ){ - sqlite3AppendSpace(pAccum, nspace); - } - } + width -= length; + if( width>0 && !flag_leftjustify ) sqlite3AppendSpace(pAccum, width); + sqlite3StrAccumAppend(pAccum, bufpt, length); + if( width>0 && flag_leftjustify ) sqlite3AppendSpace(pAccum, width); + if( zExtra ) sqlite3_free(zExtra); }/* End for loop over the format string */ } /* End of function */ /* -** Append N bytes of text from z to the StrAccum object. +** Enlarge the memory allocation on a StrAccum object so that it is +** able to accept at least N more bytes of text. +** +** Return the number of bytes of text that StrAccum is able to accept +** after the attempted enlargement. The value returned might be zero. +*/ +static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ + char *zNew; + assert( p->nChar+N >= p->nAlloc ); /* Only called if really needed */ + if( p->accError ){ + testcase(p->accError==STRACCUM_TOOBIG); + testcase(p->accError==STRACCUM_NOMEM); + return 0; + } + if( !p->useMalloc ){ + N = p->nAlloc - p->nChar - 1; + setStrAccumError(p, STRACCUM_TOOBIG); + return N; + }else{ + char *zOld = (p->zText==p->zBase ? 0 : p->zText); + i64 szNew = p->nChar; + szNew += N + 1; + if( szNew > p->mxAlloc ){ + sqlite3StrAccumReset(p); + setStrAccumError(p, STRACCUM_TOOBIG); + return 0; + }else{ + p->nAlloc = (int)szNew; + } + if( p->useMalloc==1 ){ + zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc); + }else{ + zNew = sqlite3_realloc(zOld, p->nAlloc); + } + if( zNew ){ + assert( p->zText!=0 || p->nChar==0 ); + if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar); + p->zText = zNew; + }else{ + sqlite3StrAccumReset(p); + setStrAccumError(p, STRACCUM_NOMEM); + return 0; + } + } + return N; +} + +/* +** Append N space characters to the given string buffer. +*/ +SQLITE_PRIVATE void sqlite3AppendSpace(StrAccum *p, int N){ + if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ) return; + while( (N--)>0 ) p->zText[p->nChar++] = ' '; +} + +/* +** The StrAccum "p" is not large enough to accept N new bytes of z[]. +** So enlarge if first, then do the append. +** +** This is a helper routine to sqlite3StrAccumAppend() that does special-case +** work (enlarging the buffer) using tail recursion, so that the +** sqlite3StrAccumAppend() routine can use fast calling semantics. +*/ +static void enlargeAndAppend(StrAccum *p, const char *z, int N){ + N = sqlite3StrAccumEnlarge(p, N); + if( N>0 ){ + memcpy(&p->zText[p->nChar], z, N); + p->nChar += N; + } +} + +/* +** Append N bytes of text from z to the StrAccum object. Increase the +** size of the memory allocation for StrAccum if necessary. */ SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ assert( z!=0 ); @@ -20786,43 +21331,8 @@ SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ assert( N>=0 ); assert( p->accError==0 || p->nAlloc==0 ); if( p->nChar+N >= p->nAlloc ){ - char *zNew; - if( p->accError ){ - testcase(p->accError==STRACCUM_TOOBIG); - testcase(p->accError==STRACCUM_NOMEM); - return; - } - if( !p->useMalloc ){ - N = p->nAlloc - p->nChar - 1; - setStrAccumError(p, STRACCUM_TOOBIG); - if( N<=0 ){ - return; - } - }else{ - char *zOld = (p->zText==p->zBase ? 0 : p->zText); - i64 szNew = p->nChar; - szNew += N + 1; - if( szNew > p->mxAlloc ){ - sqlite3StrAccumReset(p); - setStrAccumError(p, STRACCUM_TOOBIG); - return; - }else{ - p->nAlloc = (int)szNew; - } - if( p->useMalloc==1 ){ - zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc); - }else{ - zNew = sqlite3_realloc(zOld, p->nAlloc); - } - if( zNew ){ - if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar); - p->zText = zNew; - }else{ - sqlite3StrAccumReset(p); - setStrAccumError(p, STRACCUM_NOMEM); - return; - } - } + enlargeAndAppend(p,z,N); + return; } assert( p->zText ); memcpy(&p->zText[p->nChar], z, N); @@ -21344,8 +21854,8 @@ static const unsigned char sqlite3Utf8Trans1[] = { ** and rendered as themselves even though they are technically ** invalid characters. ** -** * This routine accepts an infinite number of different UTF8 encodings -** for unicode values 0x80 and greater. It do not change over-length +** * This routine accepts over-length UTF8 encodings +** for unicode values 0x80 and greater. It does not change over-length ** encodings to 0xfffd as some systems recommend. */ #define READ_UTF8(zIn, zTerm, c) \ @@ -21758,6 +22268,24 @@ SQLITE_PRIVATE void sqlite3Coverage(int x){ } #endif +/* +** Give a callback to the test harness that can be used to simulate faults +** in places where it is difficult or expensive to do so purely by means +** of inputs. +** +** The intent of the integer argument is to let the fault simulator know +** which of multiple sqlite3FaultSim() calls has been hit. +** +** Return whatever integer value the test callback returns, or return +** SQLITE_OK if no test callback is installed. +*/ +#ifndef SQLITE_OMIT_BUILTIN_TEST +SQLITE_PRIVATE int sqlite3FaultSim(int iTest){ + int (*xCallback)(int) = sqlite3GlobalConfig.xTestCallback; + return xCallback ? xCallback(iTest) : SQLITE_OK; +} +#endif + #ifndef SQLITE_OMIT_FLOATING_POINT /* ** Return true if the floating point value is Not a Number (NaN). @@ -22184,9 +22712,9 @@ static int compare2pow63(const char *zNum, int incr){ return c; } - /* -** Convert zNum to a 64-bit signed integer. +** Convert zNum to a 64-bit signed integer. zNum must be decimal. This +** routine does *not* accept hexadecimal notation. ** ** If the zNum value is representable as a 64-bit twos-complement ** integer, then write that value into *pNum and return 0. @@ -22274,10 +22802,44 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc } } +/* +** Transform a UTF-8 integer literal, in either decimal or hexadecimal, +** into a 64-bit signed integer. This routine accepts hexadecimal literals, +** whereas sqlite3Atoi64() does not. +** +** Returns: +** +** 0 Successful transformation. Fits in a 64-bit signed integer. +** 1 Integer too large for a 64-bit signed integer or is malformed +** 2 Special case of 9223372036854775808 +*/ +SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){ +#ifndef SQLITE_OMIT_HEX_INTEGER + if( z[0]=='0' + && (z[1]=='x' || z[1]=='X') + && sqlite3Isxdigit(z[2]) + ){ + u64 u = 0; + int i, k; + for(i=2; z[i]=='0'; i++){} + for(k=i; sqlite3Isxdigit(z[k]); k++){ + u = u*16 + sqlite3HexToInt(z[k]); + } + memcpy(pOut, &u, 8); + return (z[k]==0 && k-i<=16) ? 0 : 1; + }else +#endif /* SQLITE_OMIT_HEX_INTEGER */ + { + return sqlite3Atoi64(z, pOut, sqlite3Strlen30(z), SQLITE_UTF8); + } +} + /* ** If zNum represents an integer that will fit in 32-bits, then set ** *pValue to that integer and return true. Otherwise return false. ** +** This routine accepts both decimal and hexadecimal notation for integers. +** ** Any non-numeric characters that following zNum are ignored. ** This is different from sqlite3Atoi64() which requires the ** input number to be zero-terminated. @@ -22292,7 +22854,25 @@ SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){ }else if( zNum[0]=='+' ){ zNum++; } - while( zNum[0]=='0' ) zNum++; +#ifndef SQLITE_OMIT_HEX_INTEGER + else if( zNum[0]=='0' + && (zNum[1]=='x' || zNum[1]=='X') + && sqlite3Isxdigit(zNum[2]) + ){ + u32 u = 0; + zNum += 2; + while( zNum[0]=='0' ) zNum++; + for(i=0; sqlite3Isxdigit(zNum[i]) && i<8; i++){ + u = u*16 + sqlite3HexToInt(zNum[i]); + } + if( (u&0x80000000)==0 && sqlite3Isxdigit(zNum[i])==0 ){ + memcpy(pValue, &u, 4); + return 1; + }else{ + return 0; + } + } +#endif for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){ v = v*10 + c; } @@ -22973,8 +23553,8 @@ SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst a, LogEst b){ } /* -** Convert an integer into a LogEst. In other words, compute a -** good approximatation for 10*log2(x). +** Convert an integer into a LogEst. In other words, compute an +** approximation for 10*log2(x). */ SQLITE_PRIVATE LogEst sqlite3LogEst(u64 x){ static LogEst a[] = { 0, 2, 3, 5, 6, 7, 8, 9 }; @@ -23330,7 +23910,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 11 */ "Checkpoint" OpHelp(""), /* 12 */ "JournalMode" OpHelp(""), /* 13 */ "Vacuum" OpHelp(""), - /* 14 */ "VFilter" OpHelp("iPlan=r[P3] zPlan='P4'"), + /* 14 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"), /* 15 */ "VUpdate" OpHelp("data=r[P3@P2]"), /* 16 */ "Goto" OpHelp(""), /* 17 */ "Gosub" OpHelp(""), @@ -23357,7 +23937,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 38 */ "MustBeInt" OpHelp(""), /* 39 */ "RealAffinity" OpHelp(""), /* 40 */ "Permutation" OpHelp(""), - /* 41 */ "Compare" OpHelp(""), + /* 41 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), /* 42 */ "Jump" OpHelp(""), /* 43 */ "Once" OpHelp(""), /* 44 */ "If" OpHelp(""), @@ -23368,30 +23948,30 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 49 */ "Count" OpHelp("r[P2]=count()"), /* 50 */ "ReadCookie" OpHelp(""), /* 51 */ "SetCookie" OpHelp(""), - /* 52 */ "OpenRead" OpHelp("root=P2 iDb=P3"), - /* 53 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), - /* 54 */ "OpenAutoindex" OpHelp("nColumn=P2"), - /* 55 */ "OpenEphemeral" OpHelp("nColumn=P2"), - /* 56 */ "SorterOpen" OpHelp(""), - /* 57 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), - /* 58 */ "Close" OpHelp(""), - /* 59 */ "SeekLT" OpHelp(""), - /* 60 */ "SeekLE" OpHelp(""), - /* 61 */ "SeekGE" OpHelp(""), - /* 62 */ "SeekGT" OpHelp(""), - /* 63 */ "Seek" OpHelp("intkey=r[P2]"), - /* 64 */ "NoConflict" OpHelp("key=r[P3@P4]"), - /* 65 */ "NotFound" OpHelp("key=r[P3@P4]"), - /* 66 */ "Found" OpHelp("key=r[P3@P4]"), - /* 67 */ "NotExists" OpHelp("intkey=r[P3]"), - /* 68 */ "Sequence" OpHelp("r[P2]=rowid"), - /* 69 */ "NewRowid" OpHelp("r[P2]=rowid"), - /* 70 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), + /* 52 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), + /* 53 */ "OpenRead" OpHelp("root=P2 iDb=P3"), + /* 54 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), + /* 55 */ "OpenAutoindex" OpHelp("nColumn=P2"), + /* 56 */ "OpenEphemeral" OpHelp("nColumn=P2"), + /* 57 */ "SorterOpen" OpHelp(""), + /* 58 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), + /* 59 */ "Close" OpHelp(""), + /* 60 */ "SeekLT" OpHelp("key=r[P3@P4]"), + /* 61 */ "SeekLE" OpHelp("key=r[P3@P4]"), + /* 62 */ "SeekGE" OpHelp("key=r[P3@P4]"), + /* 63 */ "SeekGT" OpHelp("key=r[P3@P4]"), + /* 64 */ "Seek" OpHelp("intkey=r[P2]"), + /* 65 */ "NoConflict" OpHelp("key=r[P3@P4]"), + /* 66 */ "NotFound" OpHelp("key=r[P3@P4]"), + /* 67 */ "Found" OpHelp("key=r[P3@P4]"), + /* 68 */ "NotExists" OpHelp("intkey=r[P3]"), + /* 69 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), + /* 70 */ "NewRowid" OpHelp("r[P2]=rowid"), /* 71 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), /* 72 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), - /* 73 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), - /* 74 */ "Delete" OpHelp(""), - /* 75 */ "ResetCount" OpHelp(""), + /* 73 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), + /* 74 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), + /* 75 */ "Delete" OpHelp(""), /* 76 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), /* 77 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), /* 78 */ "Ne" OpHelp("if r[P1]!=r[P3] goto P2"), @@ -23400,7 +23980,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 81 */ "Le" OpHelp("if r[P1]<=r[P3] goto P2"), /* 82 */ "Lt" OpHelp("if r[P1]=r[P3] goto P2"), - /* 84 */ "SorterCompare" OpHelp("if key(P1)!=rtrim(r[P3],P4) goto P2"), + /* 84 */ "ResetCount" OpHelp(""), /* 85 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), /* 86 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), /* 87 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<0 goto P2"), + /* 98 */ "SorterData" OpHelp("r[P2]=data"), + /* 99 */ "RowKey" OpHelp("r[P2]=key"), + /* 100 */ "RowData" OpHelp("r[P2]=data"), + /* 101 */ "Rowid" OpHelp("r[P2]=rowid"), + /* 102 */ "NullRow" OpHelp(""), + /* 103 */ "Last" OpHelp(""), + /* 104 */ "SorterSort" OpHelp(""), + /* 105 */ "Sort" OpHelp(""), + /* 106 */ "Rewind" OpHelp(""), + /* 107 */ "SorterInsert" OpHelp(""), + /* 108 */ "IdxInsert" OpHelp("key=r[P2]"), + /* 109 */ "IdxDelete" OpHelp("key=r[P2@P3]"), + /* 110 */ "IdxRowid" OpHelp("r[P2]=rowid"), + /* 111 */ "IdxLE" OpHelp("key=r[P3@P4]"), + /* 112 */ "IdxGT" OpHelp("key=r[P3@P4]"), + /* 113 */ "IdxLT" OpHelp("key=r[P3@P4]"), + /* 114 */ "IdxGE" OpHelp("key=r[P3@P4]"), + /* 115 */ "Destroy" OpHelp(""), + /* 116 */ "Clear" OpHelp(""), + /* 117 */ "ResetSorter" OpHelp(""), + /* 118 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"), + /* 119 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"), + /* 120 */ "ParseSchema" OpHelp(""), + /* 121 */ "LoadAnalysis" OpHelp(""), + /* 122 */ "DropTable" OpHelp(""), + /* 123 */ "DropIndex" OpHelp(""), + /* 124 */ "DropTrigger" OpHelp(""), + /* 125 */ "IntegrityCk" OpHelp(""), + /* 126 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), + /* 127 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), + /* 128 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), + /* 129 */ "Program" OpHelp(""), + /* 130 */ "Param" OpHelp(""), + /* 131 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), + /* 132 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), /* 133 */ "Real" OpHelp("r[P2]=P4"), - /* 134 */ "IfNeg" OpHelp("if r[P1]<0 goto P2"), - /* 135 */ "IfZero" OpHelp("r[P1]+=P3, if r[P1]==0 goto P2"), - /* 136 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), - /* 137 */ "IncrVacuum" OpHelp(""), - /* 138 */ "Expire" OpHelp(""), - /* 139 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), - /* 140 */ "VBegin" OpHelp(""), - /* 141 */ "VCreate" OpHelp(""), - /* 142 */ "VDestroy" OpHelp(""), + /* 134 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), + /* 135 */ "IfPos" OpHelp("if r[P1]>0 goto P2"), + /* 136 */ "IfNeg" OpHelp("r[P1]+=P3, if r[P1]<0 goto P2"), + /* 137 */ "IfZero" OpHelp("r[P1]+=P3, if r[P1]==0 goto P2"), + /* 138 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), + /* 139 */ "IncrVacuum" OpHelp(""), + /* 140 */ "Expire" OpHelp(""), + /* 141 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), + /* 142 */ "VBegin" OpHelp(""), /* 143 */ "ToText" OpHelp(""), /* 144 */ "ToBlob" OpHelp(""), /* 145 */ "ToNumeric" OpHelp(""), /* 146 */ "ToInt" OpHelp(""), /* 147 */ "ToReal" OpHelp(""), - /* 148 */ "VOpen" OpHelp(""), - /* 149 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), - /* 150 */ "VNext" OpHelp(""), - /* 151 */ "VRename" OpHelp(""), - /* 152 */ "Pagecount" OpHelp(""), - /* 153 */ "MaxPgcnt" OpHelp(""), - /* 154 */ "Init" OpHelp("Start at P2"), - /* 155 */ "Noop" OpHelp(""), - /* 156 */ "Explain" OpHelp(""), + /* 148 */ "VCreate" OpHelp(""), + /* 149 */ "VDestroy" OpHelp(""), + /* 150 */ "VOpen" OpHelp(""), + /* 151 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), + /* 152 */ "VNext" OpHelp(""), + /* 153 */ "VRename" OpHelp(""), + /* 154 */ "Pagecount" OpHelp(""), + /* 155 */ "MaxPgcnt" OpHelp(""), + /* 156 */ "Init" OpHelp("Start at P2"), + /* 157 */ "Noop" OpHelp(""), + /* 158 */ "Explain" OpHelp(""), }; return azName[i]; } @@ -23575,11 +24157,10 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ #include #include #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 -#include +# include #endif - -#if SQLITE_ENABLE_LOCKING_STYLE +#if SQLITE_ENABLE_LOCKING_STYLE || OS_VXWORKS # include # if OS_VXWORKS # include @@ -24007,11 +24588,16 @@ static int posixOpen(const char *zFile, int flags, int mode){ ** we are not running as root. */ static int posixFchown(int fd, uid_t uid, gid_t gid){ +#if OS_VXWORKS + return 0; +#else return geteuid() ? 0 : fchown(fd,uid,gid); +#endif } /* Forward reference */ static int openDirectory(const char*, int*); +static int unixGetpagesize(void); /* ** Many system calls are accessed through pointer-to-functions so that @@ -24062,7 +24648,7 @@ static struct unix_syscall { { "read", (sqlite3_syscall_ptr)read, 0 }, #define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent) -#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE +#if defined(USE_PREAD) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS) { "pread", (sqlite3_syscall_ptr)pread, 0 }, #else { "pread", (sqlite3_syscall_ptr)0, 0 }, @@ -24079,7 +24665,7 @@ static struct unix_syscall { { "write", (sqlite3_syscall_ptr)write, 0 }, #define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent) -#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE +#if defined(USE_PREAD) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS) { "pwrite", (sqlite3_syscall_ptr)pwrite, 0 }, #else { "pwrite", (sqlite3_syscall_ptr)0, 0 }, @@ -24133,6 +24719,9 @@ static struct unix_syscall { { "mremap", (sqlite3_syscall_ptr)0, 0 }, #endif #define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent) + { "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 }, +#define osGetpagesize ((int(*)(void))aSyscall[24].pCurrent) + #endif }; /* End of the overrideable system calls */ @@ -24446,16 +25035,6 @@ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) { case EPERM: return SQLITE_PERM; - /* EDEADLK is only possible if a call to fcntl(F_SETLKW) is made. And - ** this module never makes such a call. And the code in SQLite itself - ** asserts that SQLITE_IOERR_BLOCKED is never returned. For these reasons - ** this case is also commented out. If the system does set errno to EDEADLK, - ** the default SQLITE_IOERR_XXX code will be returned. */ -#if 0 - case EDEADLK: - return SQLITE_IOERR_BLOCKED; -#endif - #if EOPNOTSUPP!=ENOTSUP case EOPNOTSUPP: /* something went terribly awry, unless during file system support @@ -24988,9 +25567,13 @@ static int findInodeInfo( ** Return TRUE if pFile has been renamed or unlinked since it was first opened. */ static int fileHasMoved(unixFile *pFile){ +#if OS_VXWORKS + return pFile->pInode!=0 && pFile->pId!=pFile->pInode->fileId.pId; +#else struct stat buf; return pFile->pInode!=0 && - (osStat(pFile->zPath, &buf)!=0 || buf.st_ino!=pFile->pInode->fileId.ino); + (osStat(pFile->zPath, &buf)!=0 || buf.st_ino!=pFile->pInode->fileId.ino); +#endif } @@ -25603,6 +26186,13 @@ static int closeUnixFile(sqlite3_file *id){ vxworksReleaseFileId(pFile->pId); pFile->pId = 0; } +#endif +#ifdef SQLITE_UNLINK_AFTER_CLOSE + if( pFile->ctrlFlags & UNIXFILE_DELETE ){ + osUnlink(pFile->zPath); + sqlite3_free(*(char**)&pFile->zPath); + pFile->zPath = 0; + } #endif OSTRACE(("CLOSE %-3d\n", pFile->h)); OpenCounter(-1); @@ -26126,7 +26716,6 @@ static int semCheckReservedLock(sqlite3_file *id, int *pResOut) { /* Otherwise see if some other process holds it. */ if( !reserved ){ sem_t *pSem = pFile->pInode->pSem; - struct stat statBuf; if( sem_trywait(pSem)==-1 ){ int tErrno = errno; @@ -26179,7 +26768,6 @@ static int semCheckReservedLock(sqlite3_file *id, int *pResOut) { */ static int semLock(sqlite3_file *id, int eFileLock) { unixFile *pFile = (unixFile*)id; - int fd; sem_t *pSem = pFile->pInode->pSem; int rc = SQLITE_OK; @@ -27642,8 +28230,25 @@ static int unixDeviceCharacteristics(sqlite3_file *id){ return rc; } -#ifndef SQLITE_OMIT_WAL +#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 +/* +** Return the system page size. +** +** This function should not be called directly by other code in this file. +** Instead, it should be called via macro osGetpagesize(). +*/ +static int unixGetpagesize(void){ +#if defined(_BSD_SOURCE) + return getpagesize(); +#else + return (int)sysconf(_SC_PAGESIZE); +#endif +} + +#endif /* !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 */ + +#ifndef SQLITE_OMIT_WAL /* ** Object used to represent an shared memory buffer. @@ -27794,6 +28399,22 @@ static int unixShmSystemLock( return rc; } +/* +** Return the minimum number of 32KB shm regions that should be mapped at +** a time, assuming that each mapping must be an integer multiple of the +** current system page-size. +** +** Usually, this is 1. The exception seems to be systems that are configured +** to use 64KB pages - in this case each mapping must cover at least two +** shm regions. +*/ +static int unixShmRegionPerMap(void){ + int shmsz = 32*1024; /* SHM region size */ + int pgsz = osGetpagesize(); /* System page size */ + assert( ((pgsz-1)&pgsz)==0 ); /* Page size must be a power of 2 */ + if( pgszpInode->pShmNode; assert( unixMutexHeld() ); if( p && p->nRef==0 ){ + int nShmPerMap = unixShmRegionPerMap(); int i; assert( p->pInode==pFd->pInode ); sqlite3_mutex_free(p->mutex); - for(i=0; inRegion; i++){ + for(i=0; inRegion; i+=nShmPerMap){ if( p->h>=0 ){ osMunmap(p->apRegion[i], p->szRegion); }else{ @@ -28015,6 +28637,8 @@ static int unixShmMap( unixShm *p; unixShmNode *pShmNode; int rc = SQLITE_OK; + int nShmPerMap = unixShmRegionPerMap(); + int nReqRegion; /* If the shared-memory file has not yet been opened, open it now. */ if( pDbFd->pShm==0 ){ @@ -28030,9 +28654,12 @@ static int unixShmMap( assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 ); assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 ); - if( pShmNode->nRegion<=iRegion ){ + /* Minimum number of regions required to be mapped. */ + nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap; + + if( pShmNode->nRegionszRegion = szRegion; @@ -28081,17 +28708,19 @@ static int unixShmMap( /* Map the requested memory region into this processes address space. */ apNew = (char **)sqlite3_realloc( - pShmNode->apRegion, (iRegion+1)*sizeof(char *) + pShmNode->apRegion, nReqRegion*sizeof(char *) ); if( !apNew ){ rc = SQLITE_IOERR_NOMEM; goto shmpage_out; } pShmNode->apRegion = apNew; - while(pShmNode->nRegion<=iRegion){ + while( pShmNode->nRegionh>=0 ){ - pMem = osMmap(0, szRegion, + pMem = osMmap(0, nMap, pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE, MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion ); @@ -28107,8 +28736,11 @@ static int unixShmMap( } memset(pMem, 0, szRegion); } - pShmNode->apRegion[pShmNode->nRegion] = pMem; - pShmNode->nRegion++; + + for(i=0; iapRegion[pShmNode->nRegion+i] = &((char*)pMem)[szRegion*i]; + } + pShmNode->nRegion += nShmPerMap; } } @@ -28322,19 +28954,6 @@ static void unixUnmapfile(unixFile *pFd){ } } -/* -** Return the system page size. -*/ -static int unixGetPagesize(void){ -#if HAVE_MREMAP - return 512; -#elif defined(_BSD_SOURCE) - return getpagesize(); -#else - return (int)sysconf(_SC_PAGESIZE); -#endif -} - /* ** Attempt to set the size of the memory mapping maintained by file ** descriptor pFd to nNew bytes. Any existing mapping is discarded. @@ -28371,8 +28990,12 @@ static void unixRemapfile( if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE; if( pOrig ){ - const int szSyspage = unixGetPagesize(); +#if HAVE_MREMAP + i64 nReuse = pFd->mmapSize; +#else + const int szSyspage = osGetpagesize(); i64 nReuse = (pFd->mmapSize & ~(szSyspage-1)); +#endif u8 *pReq = &pOrig[nReuse]; /* Unmap any pages of the existing mapping that cannot be reused. */ @@ -29425,6 +30048,12 @@ static int unixOpen( if( isDelete ){ #if OS_VXWORKS zPath = zName; +#elif defined(SQLITE_UNLINK_AFTER_CLOSE) + zPath = sqlite3_mprintf("%s", zName); + if( zPath==0 ){ + robust_close(p, fd, __LINE__); + return SQLITE_NOMEM; + } #else osUnlink(zName); #endif @@ -29525,7 +30154,11 @@ static int unixDelete( UNUSED_PARAMETER(NotUsed); SimulateIOError(return SQLITE_IOERR_DELETE); if( osUnlink(zPath)==(-1) ){ - if( errno==ENOENT ){ + if( errno==ENOENT +#if OS_VXWORKS + || errno==0x380003 +#endif + ){ rc = SQLITE_IOERR_DELETE_NOENT; }else{ rc = unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath); @@ -31118,7 +31751,7 @@ SQLITE_API int sqlite3_os_init(void){ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ - assert( ArraySize(aSyscall)==24 ); + assert( ArraySize(aSyscall)==25 ); /* Register all VFSes defined in the aVfs[] array */ for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ @@ -31158,11 +31791,6 @@ SQLITE_API int sqlite3_os_end(void){ */ #if SQLITE_OS_WIN /* This file is used for Windows only */ -#ifdef __CYGWIN__ -# include -# include /* amalgamator: keep */ -#endif - /* ** Include code that is common to all os_*.c files */ @@ -31376,6 +32004,10 @@ SQLITE_API int sqlite3_open_file_count = 0; /************** End of os_common.h *******************************************/ /************** Continuing where we left off in os_win.c *********************/ +/* +** Include the header file for the Windows VFS. +*/ + /* ** Compiling and using WAL mode requires several APIs that are only ** available in Windows platforms based on the NT kernel. @@ -31423,18 +32055,14 @@ SQLITE_API int sqlite3_open_file_count = 0; #endif /* -** Check if the GetVersionEx[AW] functions should be considered deprecated -** and avoid using them in that case. It should be noted here that if the -** value of the SQLITE_WIN32_GETVERSIONEX pre-processor macro is zero -** (whether via this block or via being manually specified), that implies -** the underlying operating system will always be based on the Windows NT -** Kernel. +** Check to see if the GetVersionEx[AW] functions are deprecated on the +** target system. GetVersionEx was first deprecated in Win8.1. */ #ifndef SQLITE_WIN32_GETVERSIONEX # if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINBLUE -# define SQLITE_WIN32_GETVERSIONEX 0 +# define SQLITE_WIN32_GETVERSIONEX 0 /* GetVersionEx() is deprecated */ # else -# define SQLITE_WIN32_GETVERSIONEX 1 +# define SQLITE_WIN32_GETVERSIONEX 1 /* GetVersionEx() is current */ # endif #endif @@ -31506,7 +32134,7 @@ SQLITE_API int sqlite3_open_file_count = 0; ** [sometimes] not used by the code (e.g. via conditional compilation). */ #ifndef UNUSED_VARIABLE_VALUE -# define UNUSED_VARIABLE_VALUE(x) (void)(x) +# define UNUSED_VARIABLE_VALUE(x) (void)(x) #endif /* @@ -31555,7 +32183,7 @@ WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID); ** Some Microsoft compilers lack this definition. */ #ifndef INVALID_FILE_ATTRIBUTES -# define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +# define INVALID_FILE_ATTRIBUTES ((DWORD)-1) #endif #ifndef FILE_FLAG_MASK @@ -31605,7 +32233,7 @@ struct winFile { int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */ #if SQLITE_OS_WINCE LPWSTR zDeleteOnClose; /* Name of file to delete when closing */ - HANDLE hMutex; /* Mutex used to control access to shared lock */ + HANDLE hMutex; /* Mutex used to control access to shared lock */ HANDLE hShared; /* Shared memory segment used for locking */ winceLock local; /* Locks obtained by this instance of winFile */ winceLock *shared; /* Global shared lock memory for the file */ @@ -31765,10 +32393,9 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetWin32(void); ** can manually set this value to 1 to emulate Win98 behavior. */ #ifdef SQLITE_TEST -SQLITE_API int sqlite3_os_type = 0; -#elif !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ - defined(SQLITE_WIN32_HAS_ANSI) && defined(SQLITE_WIN32_HAS_WIDE) -static int sqlite3_os_type = 0; +SQLITE_API LONG volatile sqlite3_os_type = 0; +#else +static LONG volatile sqlite3_os_type = 0; #endif #ifndef SYSCALL @@ -32399,6 +33026,22 @@ static struct win_syscall { #define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \ LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[75].pCurrent) +/* +** NOTE: On some sub-platforms, the InterlockedCompareExchange "function" +** is really just a macro that uses a compiler intrinsic (e.g. x64). +** So do not try to make this is into a redefinable interface. +*/ +#if defined(InterlockedCompareExchange) + { "InterlockedCompareExchange", (SYSCALL)0, 0 }, + +#define osInterlockedCompareExchange InterlockedCompareExchange +#else + { "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 }, + +#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG volatile*, \ + LONG,LONG))aSyscall[76].pCurrent) +#endif /* defined(InterlockedCompareExchange) */ + }; /* End of the overrideable system calls */ /* @@ -32649,22 +33292,38 @@ SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){ #elif !defined(SQLITE_WIN32_HAS_WIDE) # define osIsNT() (0) #else - static int osIsNT(void){ - if( sqlite3_os_type==0 ){ -#if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WIN8 - OSVERSIONINFOW sInfo; - sInfo.dwOSVersionInfoSize = sizeof(sInfo); - osGetVersionExW(&sInfo); -#else - OSVERSIONINFOA sInfo; - sInfo.dwOSVersionInfoSize = sizeof(sInfo); - osGetVersionExA(&sInfo); +# define osIsNT() ((sqlite3_os_type==2) || sqlite3_win32_is_nt()) +#endif + +/* +** This function determines if the machine is running a version of Windows +** based on the NT kernel. +*/ +SQLITE_API int sqlite3_win32_is_nt(void){ +#if defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX + if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){ +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ + defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WIN8 + OSVERSIONINFOW sInfo; + sInfo.dwOSVersionInfoSize = sizeof(sInfo); + osGetVersionExW(&sInfo); + osInterlockedCompareExchange(&sqlite3_os_type, + (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0); +#elif defined(SQLITE_WIN32_HAS_ANSI) + OSVERSIONINFOA sInfo; + sInfo.dwOSVersionInfoSize = sizeof(sInfo); + osGetVersionExA(&sInfo); + osInterlockedCompareExchange(&sqlite3_os_type, + (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0); #endif - sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; - } - return sqlite3_os_type==2; } + return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; +#elif SQLITE_TEST + return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; +#else + return 1; #endif +} #ifdef SQLITE_WIN32_MALLOC /* @@ -32872,7 +33531,7 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){ #endif /* SQLITE_WIN32_MALLOC */ /* -** Convert a UTF-8 string to Microsoft Unicode (UTF-16?). +** Convert a UTF-8 string to Microsoft Unicode (UTF-16?). ** ** Space to hold the returned string is obtained from malloc. */ @@ -32925,7 +33584,7 @@ static char *winUnicodeToUtf8(LPCWSTR zWideFilename){ /* ** Convert an ANSI string to Microsoft Unicode, based on the ** current codepage settings for file apis. -** +** ** Space to hold the returned string is obtained ** from sqlite3_malloc. */ @@ -32999,7 +33658,7 @@ SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zFilename){ } /* -** Convert UTF-8 to multibyte character string. Space to hold the +** Convert UTF-8 to multibyte character string. Space to hold the ** returned string is obtained from sqlite3_malloc(). */ SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){ @@ -33139,11 +33798,11 @@ static int winGetLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){ ** ** This routine is invoked after an error occurs in an OS function. ** It logs a message using sqlite3_log() containing the current value of -** error code and, if possible, the human-readable equivalent from +** error code and, if possible, the human-readable equivalent from ** FormatMessage. ** ** The first argument passed to the macro should be the error code that -** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). +** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). ** The two subsequent arguments should be the name of the OS function that ** failed and the associated file-system path, if any. */ @@ -33174,7 +33833,7 @@ static int winLogErrorAtLine( /* ** The number of times that a ReadFile(), WriteFile(), and DeleteFile() -** will be retried following a locking error - probably caused by +** will be retried following a locking error - probably caused by ** antivirus software. Also the initial delay before the first retry. ** The delay increases linearly with each retry. */ @@ -33187,6 +33846,32 @@ static int winLogErrorAtLine( static int winIoerrRetry = SQLITE_WIN32_IOERR_RETRY; static int winIoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY; +/* +** The "winIoerrCanRetry1" macro is used to determine if a particular I/O +** error code obtained via GetLastError() is eligible to be retried. It +** must accept the error code DWORD as its only argument and should return +** non-zero if the error code is transient in nature and the operation +** responsible for generating the original error might succeed upon being +** retried. The argument to this macro should be a variable. +** +** Additionally, a macro named "winIoerrCanRetry2" may be defined. If it +** is defined, it will be consulted only when the macro "winIoerrCanRetry1" +** returns zero. The "winIoerrCanRetry2" macro is completely optional and +** may be used to include additional error codes in the set that should +** result in the failing I/O operation being retried by the caller. If +** defined, the "winIoerrCanRetry2" macro must exhibit external semantics +** identical to those of the "winIoerrCanRetry1" macro. +*/ +#if !defined(winIoerrCanRetry1) +#define winIoerrCanRetry1(a) (((a)==ERROR_ACCESS_DENIED) || \ + ((a)==ERROR_SHARING_VIOLATION) || \ + ((a)==ERROR_LOCK_VIOLATION) || \ + ((a)==ERROR_DEV_NOT_EXIST) || \ + ((a)==ERROR_NETNAME_DELETED) || \ + ((a)==ERROR_SEM_TIMEOUT) || \ + ((a)==ERROR_NETWORK_UNREACHABLE)) +#endif + /* ** If a ReadFile() or WriteFile() error occurs, invoke this routine ** to see if it should be retried. Return TRUE to retry. Return FALSE @@ -33200,13 +33885,18 @@ static int winRetryIoerr(int *pnRetry, DWORD *pError){ } return 0; } - if( e==ERROR_ACCESS_DENIED || - e==ERROR_LOCK_VIOLATION || - e==ERROR_SHARING_VIOLATION ){ + if( winIoerrCanRetry1(e) ){ sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry)); ++*pnRetry; return 1; } +#if defined(winIoerrCanRetry2) + else if( winIoerrCanRetry2(e) ){ + sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry)); + ++*pnRetry; + return 1; + } +#endif if( pError ){ *pError = e; } @@ -33218,7 +33908,7 @@ static int winRetryIoerr(int *pnRetry, DWORD *pError){ */ static void winLogIoerr(int nRetry){ if( nRetry ){ - sqlite3_log(SQLITE_IOERR, + sqlite3_log(SQLITE_IOERR, "delayed %dms for lock/sharing conflict", winIoerrRetryDelay*nRetry*(nRetry+1)/2 ); @@ -33312,17 +34002,17 @@ static int winceCreateLock(const char *zFilename, winFile *pFile){ /* Acquire the mutex before continuing */ winceMutexAcquire(pFile->hMutex); - - /* Since the names of named mutexes, semaphores, file mappings etc are + + /* Since the names of named mutexes, semaphores, file mappings etc are ** case-sensitive, take advantage of that by uppercasing the mutex name ** and using that as the shared filemapping name. */ osCharUpperW(zName); pFile->hShared = osCreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(winceLock), - zName); + zName); - /* Set a flag that indicates we're the first to create the memory so it + /* Set a flag that indicates we're the first to create the memory so it ** must be zero-initialized */ lastErrno = osGetLastError(); if (lastErrno == ERROR_ALREADY_EXISTS){ @@ -33333,7 +34023,7 @@ static int winceCreateLock(const char *zFilename, winFile *pFile){ /* If we succeeded in making the shared memory handle, map it. */ if( pFile->hShared ){ - pFile->shared = (winceLock*)osMapViewOfFile(pFile->hShared, + pFile->shared = (winceLock*)osMapViewOfFile(pFile->hShared, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock)); /* If mapping failed, close the shared memory handle and erase it */ if( !pFile->shared ){ @@ -33359,7 +34049,7 @@ static int winceCreateLock(const char *zFilename, winFile *pFile){ pFile->hMutex = NULL; return SQLITE_IOERR; } - + /* Initialize the shared memory if we're supposed to */ if( bInit ){ memset(pFile->shared, 0, sizeof(winceLock)); @@ -33397,13 +34087,13 @@ static void winceDestroyLock(winFile *pFile){ osCloseHandle(pFile->hShared); /* Done with the mutex */ - winceMutexRelease(pFile->hMutex); + winceMutexRelease(pFile->hMutex); osCloseHandle(pFile->hMutex); pFile->hMutex = NULL; } } -/* +/* ** An implementation of the LockFile() API of Windows for CE */ static BOOL winceLockFile( @@ -33614,8 +34304,8 @@ static BOOL winUnlockFile( #endif /* -** Move the current position of the file handle passed as the first -** argument to offset iOffset within the file. If successful, return 0. +** Move the current position of the file handle passed as the first +** argument to offset iOffset within the file. If successful, return 0. ** Otherwise, set pFile->lastErrno and return non-zero. */ static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){ @@ -33630,11 +34320,11 @@ static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){ upperBits = (LONG)((iOffset>>32) & 0x7fffffff); lowerBits = (LONG)(iOffset & 0xffffffff); - /* API oddity: If successful, SetFilePointer() returns a dword + /* API oddity: If successful, SetFilePointer() returns a dword ** containing the lower 32-bits of the new file-offset. Or, if it fails, - ** it returns INVALID_SET_FILE_POINTER. However according to MSDN, - ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine - ** whether an error has actually occurred, it is also necessary to call + ** it returns INVALID_SET_FILE_POINTER. However according to MSDN, + ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine + ** whether an error has actually occurred, it is also necessary to call ** GetLastError(). */ dwRet = osSetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); @@ -33717,7 +34407,7 @@ static int winClose(sqlite3_file *id){ int cnt = 0; while( osDeleteFileW(pFile->zDeleteOnClose)==0 - && osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff + && osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff && cnt++ < WINCE_DELETION_ATTEMPTS ){ sqlite3_win32_sleep(100); /* Wait a little before trying again */ @@ -34145,7 +34835,7 @@ static int winGetReadLock(winFile *pFile){ pFile->lastErrno = osGetLastError(); /* No need to log a failure to lock */ } - OSTRACE(("READ-LOCK file=%p, rc=%s\n", pFile->h, sqlite3ErrName(res))); + OSTRACE(("READ-LOCK file=%p, result=%d\n", pFile->h, res)); return res; } @@ -34169,7 +34859,7 @@ static int winUnlockReadLock(winFile *pFile){ winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno, "winUnlockReadLock", pFile->zPath); } - OSTRACE(("READ-UNLOCK file=%p, rc=%s\n", pFile->h, sqlite3ErrName(res))); + OSTRACE(("READ-UNLOCK file=%p, result=%d\n", pFile->h, res)); return res; } @@ -34244,8 +34934,16 @@ static int winLock(sqlite3_file *id, int locktype){ ** If you are using this code as a model for alternative VFSes, do not ** copy this retry logic. It is a hack intended for Windows only. */ - OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, rc=%s\n", - pFile->h, cnt, sqlite3ErrName(res))); + lastErrno = osGetLastError(); + OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, result=%d\n", + pFile->h, cnt, res)); + if( lastErrno==ERROR_INVALID_HANDLE ){ + pFile->lastErrno = lastErrno; + rc = SQLITE_IOERR_LOCK; + OSTRACE(("LOCK-FAIL file=%p, count=%d, rc=%s\n", + pFile->h, cnt, sqlite3ErrName(rc))); + return rc; + } if( cnt ) sqlite3_win32_sleep(1); } gotPendingLock = res; @@ -34330,7 +35028,7 @@ static int winLock(sqlite3_file *id, int locktype){ ** non-zero, otherwise zero. */ static int winCheckReservedLock(sqlite3_file *id, int *pResOut){ - int rc; + int res; winFile *pFile = (winFile*)id; SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); @@ -34338,17 +35036,17 @@ static int winCheckReservedLock(sqlite3_file *id, int *pResOut){ assert( id!=0 ); if( pFile->locktype>=RESERVED_LOCK ){ - rc = 1; - OSTRACE(("TEST-WR-LOCK file=%p, rc=%d (local)\n", pFile->h, rc)); + res = 1; + OSTRACE(("TEST-WR-LOCK file=%p, result=%d (local)\n", pFile->h, res)); }else{ - rc = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE, 0, 1, 0); - if( rc ){ + res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE, 0, 1, 0); + if( res ){ winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0); } - rc = !rc; - OSTRACE(("TEST-WR-LOCK file=%p, rc=%d (remote)\n", pFile->h, rc)); + res = !res; + OSTRACE(("TEST-WR-LOCK file=%p, result=%d (remote)\n", pFile->h, res)); } - *pResOut = rc; + *pResOut = res; OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n", pFile->h, pResOut, *pResOut)); return SQLITE_OK; @@ -34489,6 +35187,17 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } +#ifdef SQLITE_TEST + case SQLITE_FCNTL_WIN32_SET_HANDLE: { + LPHANDLE phFile = (LPHANDLE)pArg; + HANDLE hOldFile = pFile->h; + pFile->h = *phFile; + *phFile = hOldFile; + OSTRACE(("FCNTL oldFile=%p, newFile=%p, rc=SQLITE_OK\n", + hOldFile, pFile->h)); + return SQLITE_OK; + } +#endif case SQLITE_FCNTL_TEMPFILENAME: { char *zTFile = 0; int rc = winGetTempname(pFile->pVfs, &zTFile); @@ -34546,7 +35255,7 @@ static int winDeviceCharacteristics(sqlite3_file *id){ ((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0); } -/* +/* ** Windows will only let you create file view mappings ** on allocation size granularity boundaries. ** During sqlite3_os_init() we do a GetSystemInfo() @@ -34558,11 +35267,11 @@ static SYSTEM_INFO winSysInfo; /* ** Helper functions to obtain and relinquish the global mutex. The -** global mutex is used to protect the winLockInfo objects used by +** global mutex is used to protect the winLockInfo objects used by ** this file, all of which may be shared by multiple threads. ** -** Function winShmMutexHeld() is used to assert() that the global mutex -** is held when required. This function is only used as part of assert() +** Function winShmMutexHeld() is used to assert() that the global mutex +** is held when required. This function is only used as part of assert() ** statements. e.g. ** ** winShmEnterMutex() @@ -34592,10 +35301,10 @@ static int winShmMutexHeld(void) { ** this object or while reading or writing the following fields: ** ** nRef -** pNext +** pNext ** ** The following fields are read-only after the object is created: -** +** ** fid ** zFilename ** @@ -34691,7 +35400,7 @@ static int winShmSystemLock( if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0); } - + if( rc!= 0 ){ rc = SQLITE_OK; }else{ @@ -34787,7 +35496,7 @@ static int winOpenSharedMemory(winFile *pDbFd){ } pNew->zFilename = (char*)&pNew[1]; sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath); - sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename); + sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename); /* Look to see if there is an existing winShmNode that can be used. ** If no matching winShmNode currently exists, create a new one. @@ -34824,7 +35533,7 @@ static int winOpenSharedMemory(winFile *pDbFd){ } /* Check to see if another process is holding the dead-man switch. - ** If not, truncate the file to zero length. + ** If not, truncate the file to zero length. */ if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){ rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0); @@ -34853,7 +35562,7 @@ static int winOpenSharedMemory(winFile *pDbFd){ ** the cover of the winShmEnterMutex() mutex and the pointer from the ** new (struct winShm) object to the pShmNode has been set. All that is ** left to do is to link the new object into the linked list starting - ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex + ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex ** mutex. */ sqlite3_mutex_enter(pShmNode->mutex); @@ -34873,7 +35582,7 @@ shm_open_err: } /* -** Close a connection to shared-memory. Delete the underlying +** Close a connection to shared-memory. Delete the underlying ** storage if deleteFlag is true. */ static int winShmUnmap( @@ -34962,7 +35671,7 @@ static int winShmLock( if( rc==SQLITE_OK ){ p->exclMask &= ~mask; p->sharedMask &= ~mask; - } + } }else if( flags & SQLITE_SHM_SHARED ){ u16 allShared = 0; /* Union of locks held by connections other than "p" */ @@ -35001,7 +35710,7 @@ static int winShmLock( break; } } - + /* Get the exclusive locks at the system level. Then if successful ** also mark the local connection as being locked. */ @@ -35021,7 +35730,7 @@ static int winShmLock( } /* -** Implement a memory barrier or memory fence on shared memory. +** Implement a memory barrier or memory fence on shared memory. ** ** All loads and stores begun before the barrier must complete before ** any load or store begun after the barrier. @@ -35036,22 +35745,22 @@ static void winShmBarrier( } /* -** This function is called to obtain a pointer to region iRegion of the -** shared-memory associated with the database file fd. Shared-memory regions -** are numbered starting from zero. Each shared-memory region is szRegion +** This function is called to obtain a pointer to region iRegion of the +** shared-memory associated with the database file fd. Shared-memory regions +** are numbered starting from zero. Each shared-memory region is szRegion ** bytes in size. ** ** If an error occurs, an error code is returned and *pp is set to NULL. ** ** Otherwise, if the isWrite parameter is 0 and the requested shared-memory ** region has not been allocated (by any client, including one running in a -** separate process), then *pp is set to NULL and SQLITE_OK returned. If -** isWrite is non-zero and the requested shared-memory region has not yet +** separate process), then *pp is set to NULL and SQLITE_OK returned. If +** isWrite is non-zero and the requested shared-memory region has not yet ** been allocated, it is allocated by this function. ** ** If the shared-memory region has already been allocated or is allocated by -** this call as described above, then it is mapped into this processes -** address space (if it is not already), *pp is set to point to the mapped +** this call as described above, then it is mapped into this processes +** address space (if it is not already), *pp is set to point to the mapped ** memory and SQLITE_OK returned. */ static int winShmMap( @@ -35123,17 +35832,17 @@ static int winShmMap( while( pShmNode->nRegion<=iRegion ){ HANDLE hMap = NULL; /* file-mapping handle */ void *pMap = 0; /* Mapped memory region */ - + #if SQLITE_OS_WINRT hMap = osCreateFileMappingFromApp(pShmNode->hFile.h, NULL, PAGE_READWRITE, nByte, NULL ); #elif defined(SQLITE_WIN32_HAS_WIDE) - hMap = osCreateFileMappingW(pShmNode->hFile.h, + hMap = osCreateFileMappingW(pShmNode->hFile.h, NULL, PAGE_READWRITE, 0, nByte, NULL ); #elif defined(SQLITE_WIN32_HAS_ANSI) - hMap = osCreateFileMappingA(pShmNode->hFile.h, + hMap = osCreateFileMappingA(pShmNode->hFile.h, NULL, PAGE_READWRITE, 0, nByte, NULL ); #endif @@ -35230,14 +35939,14 @@ static int winUnmapfile(winFile *pFile){ /* ** Memory map or remap the file opened by file-descriptor pFd (if the file -** is already mapped, the existing mapping is replaced by the new). Or, if -** there already exists a mapping for this file, and there are still +** is already mapped, the existing mapping is replaced by the new). Or, if +** there already exists a mapping for this file, and there are still ** outstanding xFetch() references to it, this function is a no-op. ** -** If parameter nByte is non-negative, then it is the requested size of -** the mapping to create. Otherwise, if nByte is less than zero, then the +** If parameter nByte is non-negative, then it is the requested size of +** the mapping to create. Otherwise, if nByte is less than zero, then the ** requested size is the size of the file on disk. The actual size of the -** created mapping is either the requested size or the value configured +** created mapping is either the requested size or the value configured ** using SQLITE_FCNTL_MMAP_SIZE, whichever is smaller. ** ** SQLITE_OK is returned if no error occurs (even if the mapping is not @@ -35266,7 +35975,7 @@ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){ nMap = pFd->mmapSizeMax; } nMap &= ~(sqlite3_int64)(winSysInfo.dwPageSize - 1); - + if( nMap==0 && pFd->mmapSize>0 ){ winUnmapfile(pFd); } @@ -35338,7 +36047,7 @@ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){ ** Finally, if an error does occur, return an SQLite error code. The final ** value of *pp is undefined in this case. ** -** If this function does return a pointer, the caller must eventually +** If this function does return a pointer, the caller must eventually ** release the reference by calling winUnfetch(). */ static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){ @@ -35373,20 +36082,20 @@ static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){ } /* -** If the third argument is non-NULL, then this function releases a +** If the third argument is non-NULL, then this function releases a ** reference obtained by an earlier call to winFetch(). The second ** argument passed to this function must be the same as the corresponding -** argument that was passed to the winFetch() invocation. +** argument that was passed to the winFetch() invocation. ** -** Or, if the third argument is NULL, then this function is being called -** to inform the VFS layer that, according to POSIX, any existing mapping +** Or, if the third argument is NULL, then this function is being called +** to inform the VFS layer that, according to POSIX, any existing mapping ** may now be invalid and should be unmapped. */ static int winUnfetch(sqlite3_file *fd, i64 iOff, void *p){ #if SQLITE_MAX_MMAP_SIZE>0 winFile *pFd = (winFile*)fd; /* The underlying database file */ - /* If p==0 (unmap the entire file) then there must be no outstanding + /* If p==0 (unmap the entire file) then there must be no outstanding ** xFetch references. Or, if p!=0 (meaning it is an xFetch reference), ** then there must be at least one outstanding. */ assert( (p==0)==(pFd->nFetchOut==0) ); @@ -35532,7 +36241,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this - ** function failing. + ** function failing. */ SimulateIOError( return SQLITE_IOERR ); @@ -35714,7 +36423,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ } /* - ** Check that the output buffer is large enough for the temporary file + ** Check that the output buffer is large enough for the temporary file ** name in the following format: ** ** "/etilqs_XXXXXXXXXXXXXXX\0\0" @@ -35817,8 +36526,8 @@ static int winOpen( #ifndef NDEBUG int isOpenJournal = (isCreate && ( - eType==SQLITE_OPEN_MASTER_JOURNAL - || eType==SQLITE_OPEN_MAIN_JOURNAL + eType==SQLITE_OPEN_MASTER_JOURNAL + || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_WAL )); #endif @@ -35826,9 +36535,9 @@ static int winOpen( OSTRACE(("OPEN name=%s, pFile=%p, flags=%x, pOutFlags=%p\n", zUtf8Name, id, flags, pOutFlags)); - /* Check the following statements are true: + /* Check the following statements are true: ** - ** (a) Exactly one of the READWRITE and READONLY flags must be set, and + ** (a) Exactly one of the READWRITE and READONLY flags must be set, and ** (b) if CREATE is set, then READWRITE must also be set, and ** (c) if EXCLUSIVE is set, then CREATE must also be set. ** (d) if DELETEONCLOSE is set, then CREATE must also be set. @@ -35838,7 +36547,7 @@ static int winOpen( assert(isExclusive==0 || isCreate); assert(isDelete==0 || isCreate); - /* The main DB, main journal, WAL file and master journal are never + /* The main DB, main journal, WAL file and master journal are never ** automatically deleted. Nor are they ever temporary files. */ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB ); assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL ); @@ -35846,9 +36555,9 @@ static int winOpen( assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL ); /* Assert that the upper layer has set one of the "file-type" flags. */ - assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB - || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL - || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL + assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB + || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL + || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL ); @@ -35863,8 +36572,8 @@ static int winOpen( } #endif - /* If the second argument to this function is NULL, generate a - ** temporary file name to use + /* If the second argument to this function is NULL, generate a + ** temporary file name to use */ if( !zUtf8Name ){ assert( isDelete && !isOpenJournal ); @@ -35904,8 +36613,8 @@ static int winOpen( dwDesiredAccess = GENERIC_READ; } - /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is - ** created. SQLite doesn't use it to indicate "exclusive access" + /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is + ** created. SQLite doesn't use it to indicate "exclusive access" ** as it is usually understood. */ if( isExclusive ){ @@ -35994,7 +36703,7 @@ static int winOpen( sqlite3_free(zConverted); sqlite3_free(zTmpname); if( isReadWrite && !isExclusive ){ - return winOpen(pVfs, zName, id, + return winOpen(pVfs, zName, id, ((flags|SQLITE_OPEN_READONLY) & ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags); @@ -36203,14 +36912,14 @@ static int winAccess( WIN32_FILE_ATTRIBUTE_DATA sAttrData; memset(&sAttrData, 0, sizeof(sAttrData)); while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted, - GetFileExInfoStandard, + GetFileExInfoStandard, &sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){} if( rc ){ /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file ** as if it does not exist. */ if( flags==SQLITE_ACCESS_EXISTS - && sAttrData.nFileSizeHigh==0 + && sAttrData.nFileSizeHigh==0 && sAttrData.nFileSizeLow==0 ){ attr = INVALID_FILE_ATTRIBUTES; }else{ @@ -36309,7 +37018,7 @@ static int winFullPathname( int nFull, /* Size of output buffer in bytes */ char *zFull /* Output buffer */ ){ - + #if defined(__CYGWIN__) SimulateIOError( return SQLITE_ERROR ); UNUSED_PARAMETER(nFull); @@ -36622,12 +37331,12 @@ SQLITE_API int sqlite3_current_time = 0; /* Fake system time in seconds since 1 ** epoch of noon in Greenwich on November 24, 4714 B.C according to the ** proleptic Gregorian calendar. ** -** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date +** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date ** cannot be found. */ static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){ - /* FILETIME structure is a 64-bit value representing the number of - 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). + /* FILETIME structure is a 64-bit value representing the number of + 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). */ FILETIME ft; static const sqlite3_int64 winFiletimeEpoch = 23058135*(sqlite3_int64)8640000; @@ -36635,7 +37344,7 @@ static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){ static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000; #endif /* 2^32 - to avoid use of LL and warnings in gcc */ - static const sqlite3_int64 max32BitValue = + static const sqlite3_int64 max32BitValue = (sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 + (sqlite3_int64)294967296; @@ -36651,7 +37360,7 @@ static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){ #endif *piNow = winFiletimeEpoch + - ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) + + ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) + (sqlite3_int64)ft.dwLowDateTime)/(sqlite3_int64)10000; #ifdef SQLITE_TEST @@ -36770,7 +37479,7 @@ SQLITE_API int sqlite3_os_init(void){ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ - assert( ArraySize(aSyscall)==76 ); + assert( ArraySize(aSyscall)==77 ); /* get memory map allocation granularity */ memset(&winSysInfo, 0, sizeof(SYSTEM_INFO)); @@ -36788,10 +37497,10 @@ SQLITE_API int sqlite3_os_init(void){ sqlite3_vfs_register(&winLongPathVfs, 0); #endif - return SQLITE_OK; + return SQLITE_OK; } -SQLITE_API int sqlite3_os_end(void){ +SQLITE_API int sqlite3_os_end(void){ #if SQLITE_OS_WINRT if( sleepObj!=NULL ){ osCloseHandle(sleepObj); @@ -38999,8 +39708,8 @@ struct RowSet { struct RowSetEntry *pFresh; /* Source of new entry objects */ struct RowSetEntry *pForest; /* List of binary trees of entries */ u16 nFresh; /* Number of objects on pFresh */ - u8 rsFlags; /* Various flags */ - u8 iBatch; /* Current insert batch */ + u16 rsFlags; /* Various flags */ + int iBatch; /* Current insert batch */ }; /* @@ -39334,7 +40043,7 @@ SQLITE_PRIVATE int sqlite3RowSetNext(RowSet *p, i64 *pRowid){ ** on pRowSet->pEntry, then sort those entires into the forest at ** pRowSet->pForest so that they can be tested. */ -SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 iRowid){ +SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 iRowid){ struct RowSetEntry *p, *pTree; /* This routine is never called after sqlite3RowSetNext() */ @@ -40163,7 +40872,8 @@ struct Pager { u8 ckptSyncFlags; /* SYNC_NORMAL or SYNC_FULL for checkpoint */ u8 walSyncFlags; /* SYNC_NORMAL or SYNC_FULL for wal writes */ u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */ - u8 tempFile; /* zFilename is a temporary file */ + u8 tempFile; /* zFilename is a temporary or immutable file */ + u8 noLock; /* Do not lock (except in WAL mode) */ u8 readOnly; /* True for a read-only database */ u8 memDb; /* True to inhibit all file I/O */ @@ -40628,7 +41338,7 @@ static int pagerUnlockDb(Pager *pPager, int eLock){ assert( eLock!=NO_LOCK || pagerUseWal(pPager)==0 ); if( isOpen(pPager->fd) ){ assert( pPager->eLock>=eLock ); - rc = sqlite3OsUnlock(pPager->fd, eLock); + rc = pPager->noLock ? SQLITE_OK : sqlite3OsUnlock(pPager->fd, eLock); if( pPager->eLock!=UNKNOWN_LOCK ){ pPager->eLock = (u8)eLock; } @@ -40652,7 +41362,7 @@ static int pagerLockDb(Pager *pPager, int eLock){ assert( eLock==SHARED_LOCK || eLock==RESERVED_LOCK || eLock==EXCLUSIVE_LOCK ); if( pPager->eLockeLock==UNKNOWN_LOCK ){ - rc = sqlite3OsLock(pPager->fd, eLock); + rc = pPager->noLock ? SQLITE_OK : sqlite3OsLock(pPager->fd, eLock); if( rc==SQLITE_OK && (pPager->eLock!=UNKNOWN_LOCK||eLock==EXCLUSIVE_LOCK) ){ pPager->eLock = (u8)eLock; IOTRACE(("LOCK %p %d\n", pPager, eLock)) @@ -41161,12 +41871,11 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){ if( !zMaster || pPager->journalMode==PAGER_JOURNALMODE_MEMORY - || pPager->journalMode==PAGER_JOURNALMODE_OFF + || !isOpen(pPager->jfd) ){ return SQLITE_OK; } pPager->setMaster = 1; - assert( isOpen(pPager->jfd) ); assert( pPager->journalHdr <= pPager->journalOff ); /* Calculate the length in bytes and the checksum of zMaster */ @@ -44212,30 +44921,38 @@ SQLITE_PRIVATE int sqlite3PagerOpen( ** + The value returned by sqlite3OsSectorSize() ** + The largest page size that can be written atomically. */ - if( rc==SQLITE_OK && !readOnly ){ - setSectorSize(pPager); - assert(SQLITE_DEFAULT_PAGE_SIZE<=SQLITE_MAX_DEFAULT_PAGE_SIZE); - if( szPageDfltsectorSize ){ - if( pPager->sectorSize>SQLITE_MAX_DEFAULT_PAGE_SIZE ){ - szPageDflt = SQLITE_MAX_DEFAULT_PAGE_SIZE; - }else{ - szPageDflt = (u32)pPager->sectorSize; - } - } -#ifdef SQLITE_ENABLE_ATOMIC_WRITE - { - int iDc = sqlite3OsDeviceCharacteristics(pPager->fd); - int ii; - assert(SQLITE_IOCAP_ATOMIC512==(512>>8)); - assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8)); - assert(SQLITE_MAX_DEFAULT_PAGE_SIZE<=65536); - for(ii=szPageDflt; ii<=SQLITE_MAX_DEFAULT_PAGE_SIZE; ii=ii*2){ - if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ){ - szPageDflt = ii; + if( rc==SQLITE_OK ){ + int iDc = sqlite3OsDeviceCharacteristics(pPager->fd); + if( !readOnly ){ + setSectorSize(pPager); + assert(SQLITE_DEFAULT_PAGE_SIZE<=SQLITE_MAX_DEFAULT_PAGE_SIZE); + if( szPageDfltsectorSize ){ + if( pPager->sectorSize>SQLITE_MAX_DEFAULT_PAGE_SIZE ){ + szPageDflt = SQLITE_MAX_DEFAULT_PAGE_SIZE; + }else{ + szPageDflt = (u32)pPager->sectorSize; + } + } +#ifdef SQLITE_ENABLE_ATOMIC_WRITE + { + int ii; + assert(SQLITE_IOCAP_ATOMIC512==(512>>8)); + assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8)); + assert(SQLITE_MAX_DEFAULT_PAGE_SIZE<=65536); + for(ii=szPageDflt; ii<=SQLITE_MAX_DEFAULT_PAGE_SIZE; ii=ii*2){ + if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ){ + szPageDflt = ii; + } } } - } #endif + } + pPager->noLock = sqlite3_uri_boolean(zFilename, "nolock", 0); + if( (iDc & SQLITE_IOCAP_IMMUTABLE)!=0 + || sqlite3_uri_boolean(zFilename, "immutable", 0) ){ + vfsFlags |= SQLITE_OPEN_READONLY; + goto act_like_temp_file; + } } }else{ /* If a temporary file is requested, it is not opened immediately. @@ -44245,10 +44962,14 @@ SQLITE_PRIVATE int sqlite3PagerOpen( ** This branch is also run for an in-memory database. An in-memory ** database is the same as a temp-file that is never written out to ** disk and uses an in-memory rollback journal. + ** + ** This branch also runs for files marked as immutable. */ +act_like_temp_file: tempFile = 1; - pPager->eState = PAGER_READER; - pPager->eLock = EXCLUSIVE_LOCK; + pPager->eState = PAGER_READER; /* Pretend we already have a lock */ + pPager->eLock = EXCLUSIVE_LOCK; /* Pretend we are in EXCLUSIVE locking mode */ + pPager->noLock = 1; /* Do no locking */ readOnly = (vfsFlags&SQLITE_OPEN_READONLY); } @@ -44289,9 +45010,6 @@ SQLITE_PRIVATE int sqlite3PagerOpen( /* pPager->nPage = 0; */ pPager->mxPgno = SQLITE_MAX_PAGE_COUNT; /* pPager->state = PAGER_UNLOCK; */ -#if 0 - assert( pPager->state == (tempFile ? PAGER_EXCLUSIVE : PAGER_UNLOCK) ); -#endif /* pPager->errMask = 0; */ pPager->tempFile = (u8)tempFile; assert( tempFile==PAGER_LOCKINGMODE_NORMAL @@ -48858,8 +49576,8 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ ** calls to sqlite3OsSleep() have a delay of 1 microsecond. Really this ** is more of a scheduler yield than an actual delay. But on the 10th ** an subsequent retries, the delays start becoming longer and longer, - ** so that on the 100th (and last) RETRY we delay for 21 milliseconds. - ** The total delay time before giving up is less than 1 second. + ** so that on the 100th (and last) RETRY we delay for 323 milliseconds. + ** The total delay time before giving up is less than 10 seconds. */ if( cnt>5 ){ int nDelay = 1; /* Pause time in microseconds */ @@ -48867,7 +49585,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ VVA_ONLY( pWal->lockError = 1; ) return SQLITE_PROTOCOL; } - if( cnt>=10 ) nDelay = (cnt-9)*238; /* Max delay 21ms. Total delay 996ms */ + if( cnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39; sqlite3OsSleep(pWal->pVfs, nDelay); } @@ -50373,27 +51091,30 @@ struct BtCursor { BtShared *pBt; /* The BtShared this cursor points to */ BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */ struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */ -#ifndef SQLITE_OMIT_INCRBLOB Pgno *aOverflow; /* Cache of overflow page locations */ -#endif - Pgno pgnoRoot; /* The root page of this tree */ CellInfo info; /* A parse of the cell we are pointing at */ - i64 nKey; /* Size of pKey, or last integer key */ - void *pKey; /* Saved key that was cursor's last known position */ + i64 nKey; /* Size of pKey, or last integer key */ + void *pKey; /* Saved key that was cursor last known position */ + Pgno pgnoRoot; /* The root page of this tree */ + int nOvflAlloc; /* Allocated size of aOverflow[] array */ int skipNext; /* Prev() is noop if negative. Next() is noop if positive */ - u8 wrFlag; /* True if writable */ - u8 atLast; /* Cursor pointing to the last entry */ - u8 validNKey; /* True if info.nKey is valid */ + u8 curFlags; /* zero or more BTCF_* flags defined below */ u8 eState; /* One of the CURSOR_XXX constants (see below) */ -#ifndef SQLITE_OMIT_INCRBLOB - u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */ -#endif u8 hints; /* As configured by CursorSetHints() */ i16 iPage; /* Index of current page in apPage */ u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */ MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */ }; +/* +** Legal values for BtCursor.curFlags +*/ +#define BTCF_WriteFlag 0x01 /* True if a write cursor */ +#define BTCF_ValidNKey 0x02 /* True if info.nKey is valid */ +#define BTCF_ValidOvfl 0x04 /* True if aOverflow is valid */ +#define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */ +#define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */ + /* ** Potential values for BtCursor.eState. ** @@ -50980,7 +51701,7 @@ static int hasSharedCacheTableLock( ** the correct locks are held. So do not bother - just return true. ** This case does not come up very often anyhow. */ - if( isIndex && (!pSchema || (pSchema->flags&DB_SchemaLoaded)==0) ){ + if( isIndex && (!pSchema || (pSchema->schemaFlags&DB_SchemaLoaded)==0) ){ return 1; } @@ -51264,16 +51985,11 @@ static int cursorHoldsMutex(BtCursor *p){ } #endif - -#ifndef SQLITE_OMIT_INCRBLOB /* -** Invalidate the overflow page-list cache for cursor pCur, if any. +** Invalidate the overflow cache of the cursor passed as the first argument. +** on the shared btree structure pBt. */ -static void invalidateOverflowCache(BtCursor *pCur){ - assert( cursorHoldsMutex(pCur) ); - sqlite3_free(pCur->aOverflow); - pCur->aOverflow = 0; -} +#define invalidateOverflowCache(pCur) (pCur->curFlags &= ~BTCF_ValidOvfl) /* ** Invalidate the overflow page-list cache for all cursors opened @@ -51287,6 +52003,7 @@ static void invalidateAllOverflowCache(BtShared *pBt){ } } +#ifndef SQLITE_OMIT_INCRBLOB /* ** This function is called before modifying the contents of a table ** to invalidate any incrblob cursors that are open on the @@ -51309,16 +52026,14 @@ static void invalidateIncrblobCursors( BtShared *pBt = pBtree->pBt; assert( sqlite3BtreeHoldsMutex(pBtree) ); for(p=pBt->pCursor; p; p=p->pNext){ - if( p->isIncrblobHandle && (isClearTable || p->info.nKey==iRow) ){ + if( (p->curFlags & BTCF_Incrblob)!=0 && (isClearTable || p->info.nKey==iRow) ){ p->eState = CURSOR_INVALID; } } } #else - /* Stub functions when INCRBLOB is omitted */ - #define invalidateOverflowCache(x) - #define invalidateAllOverflowCache(x) + /* Stub function when INCRBLOB is omitted */ #define invalidateIncrblobCursors(x,y,z) #endif /* SQLITE_OMIT_INCRBLOB */ @@ -51564,20 +52279,32 @@ static int btreeRestoreCursorPosition(BtCursor *pCur){ ** at is deleted out from under them. ** ** This routine returns an error code if something goes wrong. The -** integer *pHasMoved is set to one if the cursor has moved and 0 if not. +** integer *pHasMoved is set as follows: +** +** 0: The cursor is unchanged +** 1: The cursor is still pointing at the same row, but the pointers +** returned by sqlite3BtreeKeyFetch() or sqlite3BtreeDataFetch() +** might now be invalid because of a balance() or other change to the +** b-tree. +** 2: The cursor is no longer pointing to the row. The row might have +** been deleted out from under the cursor. */ SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){ int rc; + if( pCur->eState==CURSOR_VALID ){ + *pHasMoved = 0; + return SQLITE_OK; + } rc = restoreCursorPosition(pCur); if( rc ){ - *pHasMoved = 1; + *pHasMoved = 2; return rc; } if( pCur->eState!=CURSOR_VALID || NEVER(pCur->skipNext!=0) ){ - *pHasMoved = 1; + *pHasMoved = 2; }else{ - *pHasMoved = 0; + *pHasMoved = 1; } return SQLITE_OK; } @@ -52444,7 +53171,7 @@ static Pgno btreePagecount(BtShared *pBt){ SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){ assert( sqlite3BtreeHoldsMutex(p) ); assert( ((p->pBt->nPage)&0x8000000)==0 ); - return (int)btreePagecount(p->pBt); + return btreePagecount(p->pBt); } /* @@ -52979,6 +53706,7 @@ SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){ return SQLITE_OK; } +#if SQLITE_MAX_MMAP_SIZE>0 /* ** Change the limit on the amount of the database file that may be ** memory mapped. @@ -52991,6 +53719,7 @@ SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){ sqlite3BtreeLeave(p); return SQLITE_OK; } +#endif /* SQLITE_MAX_MMAP_SIZE>0 */ /* ** Change the way data is synced to disk in order to increase or decrease @@ -53367,7 +54096,8 @@ static int countValidCursors(BtShared *pBt, int wrOnly){ BtCursor *pCur; int r = 0; for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ - if( (wrOnly==0 || pCur->wrFlag) && pCur->eState!=CURSOR_FAULT ) r++; + if( (wrOnly==0 || (pCur->curFlags & BTCF_WriteFlag)!=0) + && pCur->eState!=CURSOR_FAULT ) r++; } return r; } @@ -54442,7 +55172,8 @@ static int btreeCursor( pCur->pKeyInfo = pKeyInfo; pCur->pBtree = p; pCur->pBt = pBt; - pCur->wrFlag = (u8)wrFlag; + assert( wrFlag==0 || wrFlag==BTCF_WriteFlag ); + pCur->curFlags = wrFlag; pCur->pNext = pBt->pCursor; if( pCur->pNext ){ pCur->pNext->pPrev = pCur; @@ -54512,7 +55243,7 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){ releasePage(pCur->apPage[i]); } unlockBtreeIfUnused(pBt); - invalidateOverflowCache(pCur); + sqlite3DbFree(pBtree->db, pCur->aOverflow); /* sqlite3_free(pCur); */ sqlite3BtreeLeave(pBtree); } @@ -54551,7 +55282,7 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){ if( pCur->info.nSize==0 ){ int iPage = pCur->iPage; btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); - pCur->validNKey = 1; + pCur->curFlags |= BTCF_ValidNKey; }else{ assertCellInfo(pCur); } @@ -54561,8 +55292,8 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){ #define getCellInfo(pCur) \ if( pCur->info.nSize==0 ){ \ int iPage = pCur->iPage; \ - btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \ - pCur->validNKey = 1; \ + btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \ + pCur->curFlags |= BTCF_ValidNKey; \ }else{ \ assertCellInfo(pCur); \ } @@ -54733,10 +55464,12 @@ static int copyPayload( /* ** This function is used to read or overwrite payload information -** for the entry that the pCur cursor is pointing to. If the eOp -** parameter is 0, this is a read operation (data copied into -** buffer pBuf). If it is non-zero, a write (data copied from -** buffer pBuf). +** for the entry that the pCur cursor is pointing to. The eOp +** argument is interpreted as follows: +** +** 0: The operation is a read. Populate the overflow cache. +** 1: The operation is a write. Populate the overflow cache. +** 2: The operation is a read. Do not populate the overflow cache. ** ** A total of "amt" bytes are read or written beginning at "offset". ** Data is read to or from the buffer pBuf. @@ -54744,11 +55477,11 @@ static int copyPayload( ** The content being read or written might appear on the main page ** or be scattered out on multiple overflow pages. ** -** If the BtCursor.isIncrblobHandle flag is set, and the current -** cursor entry uses one or more overflow pages, this function -** allocates space for and lazily popluates the overflow page-list -** cache array (BtCursor.aOverflow). Subsequent calls use this -** cache to make seeking to the supplied offset more efficient. +** If the current cursor entry uses one or more overflow pages and the +** eOp argument is not 2, this function may allocate space for and lazily +** popluates the overflow page-list cache array (BtCursor.aOverflow). +** Subsequent calls use this cache to make seeking to the supplied offset +** more efficient. ** ** Once an overflow page-list cache has been allocated, it may be ** invalidated if some other cursor writes to the same table, or if @@ -54772,15 +55505,22 @@ static int accessPayload( int iIdx = 0; MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */ BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */ +#ifdef SQLITE_DIRECT_OVERFLOW_READ + int bEnd; /* True if reading to end of data */ +#endif assert( pPage ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->aiIdx[pCur->iPage]nCell ); assert( cursorHoldsMutex(pCur) ); + assert( eOp!=2 || offset==0 ); /* Always start from beginning for eOp==2 */ getCellInfo(pCur); aPayload = pCur->info.pCell + pCur->info.nHeader; nKey = (pPage->intKey ? 0 : (int)pCur->info.nKey); +#ifdef SQLITE_DIRECT_OVERFLOW_READ + bEnd = (offset+amt==nKey+pCur->info.nData); +#endif if( NEVER(offset+amt > nKey+pCur->info.nData) || &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] @@ -54795,7 +55535,7 @@ static int accessPayload( if( a+offset>pCur->info.nLocal ){ a = pCur->info.nLocal - offset; } - rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage); + rc = copyPayload(&aPayload[offset], pBuf, a, (eOp & 0x01), pPage->pDbPage); offset = 0; pBuf += a; amt -= a; @@ -54809,21 +55549,30 @@ static int accessPayload( nextPage = get4byte(&aPayload[pCur->info.nLocal]); -#ifndef SQLITE_OMIT_INCRBLOB - /* If the isIncrblobHandle flag is set and the BtCursor.aOverflow[] - ** has not been allocated, allocate it now. The array is sized at - ** one entry for each overflow page in the overflow chain. The - ** page number of the first overflow page is stored in aOverflow[0], - ** etc. A value of 0 in the aOverflow[] array means "not yet known" - ** (the cache is lazily populated). + /* If the BtCursor.aOverflow[] has not been allocated, allocate it now. + ** Except, do not allocate aOverflow[] for eOp==2. + ** + ** The aOverflow[] array is sized at one entry for each overflow page + ** in the overflow chain. The page number of the first overflow page is + ** stored in aOverflow[0], etc. A value of 0 in the aOverflow[] array + ** means "not yet known" (the cache is lazily populated). */ - if( pCur->isIncrblobHandle && !pCur->aOverflow ){ + if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){ int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize; - pCur->aOverflow = (Pgno *)sqlite3MallocZero(sizeof(Pgno)*nOvfl); - /* nOvfl is always positive. If it were zero, fetchPayload would have - ** been used instead of this routine. */ - if( ALWAYS(nOvfl) && !pCur->aOverflow ){ - rc = SQLITE_NOMEM; + if( nOvfl>pCur->nOvflAlloc ){ + Pgno *aNew = (Pgno*)sqlite3DbRealloc( + pCur->pBtree->db, pCur->aOverflow, nOvfl*2*sizeof(Pgno) + ); + if( aNew==0 ){ + rc = SQLITE_NOMEM; + }else{ + pCur->nOvflAlloc = nOvfl*2; + pCur->aOverflow = aNew; + } + } + if( rc==SQLITE_OK ){ + memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno)); + pCur->curFlags |= BTCF_ValidOvfl; } } @@ -54831,22 +55580,19 @@ static int accessPayload( ** entry for the first required overflow page is valid, skip ** directly to it. */ - if( pCur->aOverflow && pCur->aOverflow[offset/ovflSize] ){ + if( (pCur->curFlags & BTCF_ValidOvfl)!=0 && pCur->aOverflow[offset/ovflSize] ){ iIdx = (offset/ovflSize); nextPage = pCur->aOverflow[iIdx]; offset = (offset%ovflSize); } -#endif for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){ -#ifndef SQLITE_OMIT_INCRBLOB /* If required, populate the overflow page-list cache. */ - if( pCur->aOverflow ){ + if( (pCur->curFlags & BTCF_ValidOvfl)!=0 ){ assert(!pCur->aOverflow[iIdx] || pCur->aOverflow[iIdx]==nextPage); pCur->aOverflow[iIdx] = nextPage; } -#endif if( offset>=ovflSize ){ /* The only reason to read this page is to obtain the page @@ -54854,13 +55600,17 @@ static int accessPayload( ** data is not required. So first try to lookup the overflow ** page-list cache, if any, then fall back to the getOverflowPage() ** function. + ** + ** Note that the aOverflow[] array must be allocated because eOp!=2 + ** here. If eOp==2, then offset==0 and this branch is never taken. */ -#ifndef SQLITE_OMIT_INCRBLOB - if( pCur->aOverflow && pCur->aOverflow[iIdx+1] ){ + assert( eOp!=2 ); + assert( pCur->curFlags & BTCF_ValidOvfl ); + if( pCur->aOverflow[iIdx+1] ){ nextPage = pCur->aOverflow[iIdx+1]; - } else -#endif + }else{ rc = getOverflowPage(pBt, nextPage, 0, &nextPage); + } offset -= ovflSize; }else{ /* Need to read this page properly. It contains some of the @@ -54882,13 +55632,15 @@ static int accessPayload( ** 3) the database is file-backed, and ** 4) there is no open write-transaction, and ** 5) the database is not a WAL database, + ** 6) all data from the page is being read. ** ** then data can be read directly from the database file into the ** output buffer, bypassing the page-cache altogether. This speeds ** up loading large records that span many overflow pages. */ - if( eOp==0 /* (1) */ + if( (eOp&0x01)==0 /* (1) */ && offset==0 /* (2) */ + && (bEnd || a==ovflSize) /* (6) */ && pBt->inTransaction==TRANS_READ /* (4) */ && (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */ && pBt->pPage1->aData[19]==0x01 /* (5) */ @@ -54905,12 +55657,12 @@ static int accessPayload( { DbPage *pDbPage; rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage, - (eOp==0 ? PAGER_GET_READONLY : 0) + ((eOp&0x01)==0 ? PAGER_GET_READONLY : 0) ); if( rc==SQLITE_OK ){ aPayload = sqlite3PagerGetData(pDbPage); nextPage = get4byte(aPayload); - rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage); + rc = copyPayload(&aPayload[offset+4], pBuf, a, (eOp&0x01), pDbPage); sqlite3PagerUnref(pDbPage); offset = 0; } @@ -55004,10 +55756,7 @@ static const void *fetchPayload( assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( cursorHoldsMutex(pCur) ); assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); - if( pCur->info.nSize==0 ){ - btreeParseCell(pCur->apPage[pCur->iPage], pCur->aiIdx[pCur->iPage], - &pCur->info); - } + assert( pCur->info.nSize>0 ); *pAmt = pCur->info.nLocal; return (void*)(pCur->info.pCell + pCur->info.nHeader); } @@ -55058,14 +55807,14 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){ return SQLITE_CORRUPT_BKPT; } rc = getAndInitPage(pBt, newPgno, &pNewPage, - pCur->wrFlag==0 ? PAGER_GET_READONLY : 0); + (pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0); if( rc ) return rc; pCur->apPage[i+1] = pNewPage; pCur->aiIdx[i+1] = 0; pCur->iPage++; pCur->info.nSize = 0; - pCur->validNKey = 0; + pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); if( pNewPage->nCell<1 || pNewPage->intKey!=pCur->apPage[i]->intKey ){ return SQLITE_CORRUPT_BKPT; } @@ -55123,7 +55872,7 @@ static void moveToParent(BtCursor *pCur){ releasePage(pCur->apPage[pCur->iPage]); pCur->iPage--; pCur->info.nSize = 0; - pCur->validNKey = 0; + pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); } /* @@ -55170,7 +55919,7 @@ static int moveToRoot(BtCursor *pCur){ return SQLITE_OK; }else{ rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0], - pCur->wrFlag==0 ? PAGER_GET_READONLY : 0); + (pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0); if( rc!=SQLITE_OK ){ pCur->eState = CURSOR_INVALID; return rc; @@ -55197,8 +55946,7 @@ static int moveToRoot(BtCursor *pCur){ pCur->aiIdx[0] = 0; pCur->info.nSize = 0; - pCur->atLast = 0; - pCur->validNKey = 0; + pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl); if( pRoot->nCell>0 ){ pCur->eState = CURSOR_VALID; @@ -55261,7 +56009,7 @@ static int moveToRightmost(BtCursor *pCur){ if( rc==SQLITE_OK ){ pCur->aiIdx[pCur->iPage] = pPage->nCell-1; pCur->info.nSize = 0; - pCur->validNKey = 0; + pCur->curFlags &= ~BTCF_ValidNKey; } return rc; } @@ -55300,7 +56048,7 @@ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); /* If the cursor already points to the last entry, this is a no-op. */ - if( CURSOR_VALID==pCur->eState && pCur->atLast ){ + if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){ #ifdef SQLITE_DEBUG /* This block serves to assert() that the cursor really does point ** to the last entry in the b-tree. */ @@ -55323,7 +56071,12 @@ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ assert( pCur->eState==CURSOR_VALID ); *pRes = 0; rc = moveToRightmost(pCur); - pCur->atLast = rc==SQLITE_OK ?1:0; + if( rc==SQLITE_OK ){ + pCur->curFlags |= BTCF_AtLast; + }else{ + pCur->curFlags &= ~BTCF_AtLast; + } + } } return rc; @@ -55374,14 +56127,14 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( /* If the cursor is already positioned at the point we are trying ** to move to, then just return without doing any work */ - if( pCur->eState==CURSOR_VALID && pCur->validNKey + if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 && pCur->apPage[0]->intKey ){ if( pCur->info.nKey==intKey ){ *pRes = 0; return SQLITE_OK; } - if( pCur->atLast && pCur->info.nKeycurFlags & BTCF_AtLast)!=0 && pCur->info.nKeyisCorrupt = 0; assert( pIdxKey->default_rc==1 || pIdxKey->default_rc==0 || pIdxKey->default_rc==-1 @@ -55447,7 +56201,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( if( lwr>upr ){ c = +1; break; } }else{ assert( nCellKey==intKey ); - pCur->validNKey = 1; + pCur->curFlags |= BTCF_ValidNKey; pCur->info.nKey = nCellKey; pCur->aiIdx[pCur->iPage] = (u16)idx; if( !pPage->leaf ){ @@ -55504,7 +56258,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( goto moveto_finish; } pCur->aiIdx[pCur->iPage] = (u16)idx; - rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0); + rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 2); if( rc ){ sqlite3_free(pCellKey); goto moveto_finish; @@ -55512,6 +56266,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( c = xRecordCompare(nCell, pCellKey, pIdxKey, 0); sqlite3_free(pCellKey); } + assert( pIdxKey->isCorrupt==0 || c==0 ); if( c<0 ){ lwr = idx+1; }else if( c>0 ){ @@ -55521,6 +56276,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( *pRes = 0; rc = SQLITE_OK; pCur->aiIdx[pCur->iPage] = (u16)idx; + if( pIdxKey->isCorrupt ) rc = SQLITE_CORRUPT; goto moveto_finish; } if( lwr>upr ) break; @@ -55549,7 +56305,7 @@ moveto_next_layer: } moveto_finish: pCur->info.nSize = 0; - pCur->validNKey = 0; + pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); return rc; } @@ -55594,6 +56350,7 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ assert( *pRes==0 || *pRes==1 ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); if( pCur->eState!=CURSOR_VALID ){ + invalidateOverflowCache(pCur); rc = restoreCursorPosition(pCur); if( rc!=SQLITE_OK ){ *pRes = 0; @@ -55627,7 +56384,7 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ testcase( idx>pPage->nCell ); pCur->info.nSize = 0; - pCur->validNKey = 0; + pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); if( idx>=pPage->nCell ){ if( !pPage->leaf ){ rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8])); @@ -55688,7 +56445,7 @@ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ assert( pRes!=0 ); assert( *pRes==0 || *pRes==1 ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); - pCur->atLast = 0; + pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl); if( pCur->eState!=CURSOR_VALID ){ if( ALWAYS(pCur->eState>=CURSOR_REQUIRESEEK) ){ rc = btreeRestoreCursorPosition(pCur); @@ -55733,7 +56490,7 @@ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ moveToParent(pCur); } pCur->info.nSize = 0; - pCur->validNKey = 0; + pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); pCur->aiIdx[pCur->iPage]--; pPage = pCur->apPage[pCur->iPage]; @@ -56523,7 +57280,8 @@ static void insertCell( if( *pRC ) return; assert( i>=0 && i<=pPage->nCell+pPage->nOverflow ); - assert( pPage->nCell<=MX_CELL(pPage->pBt) && MX_CELL(pPage->pBt)<=10921 ); + assert( MX_CELL(pPage->pBt)<=10921 ); + assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB ); assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) ); assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); @@ -57758,7 +58516,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( } assert( cursorHoldsMutex(pCur) ); - assert( pCur->wrFlag && pBt->inTransaction==TRANS_WRITE + assert( (pCur->curFlags & BTCF_WriteFlag)!=0 && pBt->inTransaction==TRANS_WRITE && (pBt->btsFlags & BTS_READ_ONLY)==0 ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); @@ -57791,7 +58549,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( /* If the cursor is currently on the last row and we are appending a ** new row onto the end, set the "loc" to avoid an unnecessary btreeMoveto() ** call */ - if( pCur->validNKey && nKey>0 && pCur->info.nKey==nKey-1 ){ + if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0 && pCur->info.nKey==nKey-1 ){ loc = -1; } } @@ -57844,7 +58602,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( /* If no error has occurred and pPage has an overflow cell, call balance() ** to redistribute the cells within the tree. Since balance() may move - ** the cursor, zero the BtCursor.info.nSize and BtCursor.validNKey + ** the cursor, zero the BtCursor.info.nSize and BTCF_ValidNKey ** variables. ** ** Previous versions of SQLite called moveToRoot() to move the cursor @@ -57864,7 +58622,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( */ pCur->info.nSize = 0; if( rc==SQLITE_OK && pPage->nOverflow ){ - pCur->validNKey = 0; + pCur->curFlags &= ~(BTCF_ValidNKey); rc = balance(pCur); /* Must make sure nOverflow is reset to zero even if the balance() @@ -57896,7 +58654,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pBt->inTransaction==TRANS_WRITE ); assert( (pBt->btsFlags & BTS_READ_ONLY)==0 ); - assert( pCur->wrFlag ); + assert( pCur->curFlags & BTCF_WriteFlag ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); assert( !hasReadConflicts(p, pCur->pgnoRoot) ); @@ -58241,6 +58999,15 @@ SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){ return rc; } +/* +** Delete all information from the single table that pCur is open on. +** +** This routine only work for pCur on an ephemeral table. +*/ +SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor *pCur){ + return sqlite3BtreeClearTable(pCur->pBtree, pCur->pgnoRoot, 0); +} + /* ** Erase all information in a table and add the root of the table to ** the freelist. Except, the root of the principle table (the one on @@ -59200,7 +59967,7 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void int rc; assert( cursorHoldsMutex(pCsr) ); assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) ); - assert( pCsr->isIncrblobHandle ); + assert( pCsr->curFlags & BTCF_Incrblob ); rc = restoreCursorPosition(pCsr); if( rc!=SQLITE_OK ){ @@ -59229,7 +59996,7 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void ** (d) there are no conflicting read-locks, and ** (e) the cursor points at a valid row of an intKey table. */ - if( !pCsr->wrFlag ){ + if( (pCsr->curFlags & BTCF_WriteFlag)==0 ){ return SQLITE_READONLY; } assert( (pCsr->pBt->btsFlags & BTS_READ_ONLY)==0 @@ -59242,20 +60009,10 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void } /* -** Set a flag on this cursor to cache the locations of pages from the -** overflow list for the current row. This is used by cursors opened -** for incremental blob IO only. -** -** This function sets a flag only. The actual page location cache -** (stored in BtCursor.aOverflow[]) is allocated and used by function -** accessPayload() (the worker function for sqlite3BtreeData() and -** sqlite3BtreePutData()). +** Mark this cursor as an incremental blob cursor. */ -SQLITE_PRIVATE void sqlite3BtreeCacheOverflow(BtCursor *pCur){ - assert( cursorHoldsMutex(pCur) ); - assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); - invalidateOverflowCache(pCur); - pCur->isIncrblobHandle = 1; +SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *pCur){ + pCur->curFlags |= BTCF_Incrblob; } #endif @@ -59304,6 +60061,13 @@ SQLITE_PRIVATE void sqlite3BtreeCursorHints(BtCursor *pCsr, unsigned int mask){ pCsr->hints = mask; } +/* +** Return true if the given Btree is read-only. +*/ +SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *p){ + return (p->pBt->btsFlags & BTS_READ_ONLY)!=0; +} + /************** End of btree.c ***********************************************/ /************** Begin file backup.c ******************************************/ /* @@ -61207,6 +61971,68 @@ SQLITE_PRIVATE void sqlite3AnalyzeFunctions(void){ } } +/* +** Attempt to extract a value from pExpr and use it to construct *ppVal. +** +** If pAlloc is not NULL, then an UnpackedRecord object is created for +** pAlloc if one does not exist and the new value is added to the +** UnpackedRecord object. +** +** A value is extracted in the following cases: +** +** * (pExpr==0). In this case the value is assumed to be an SQL NULL, +** +** * The expression is a bound variable, and this is a reprepare, or +** +** * The expression is a literal value. +** +** On success, *ppVal is made to point to the extracted value. The caller +** is responsible for ensuring that the value is eventually freed. +*/ +static int stat4ValueFromExpr( + Parse *pParse, /* Parse context */ + Expr *pExpr, /* The expression to extract a value from */ + u8 affinity, /* Affinity to use */ + struct ValueNewStat4Ctx *pAlloc,/* How to allocate space. Or NULL */ + sqlite3_value **ppVal /* OUT: New value object (or NULL) */ +){ + int rc = SQLITE_OK; + sqlite3_value *pVal = 0; + sqlite3 *db = pParse->db; + + /* Skip over any TK_COLLATE nodes */ + pExpr = sqlite3ExprSkipCollate(pExpr); + + if( !pExpr ){ + pVal = valueNew(db, pAlloc); + if( pVal ){ + sqlite3VdbeMemSetNull((Mem*)pVal); + } + }else if( pExpr->op==TK_VARIABLE + || NEVER(pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE) + ){ + Vdbe *v; + int iBindVar = pExpr->iColumn; + sqlite3VdbeSetVarmask(pParse->pVdbe, iBindVar); + if( (v = pParse->pReprepare)!=0 ){ + pVal = valueNew(db, pAlloc); + if( pVal ){ + rc = sqlite3VdbeMemCopy((Mem*)pVal, &v->aVar[iBindVar-1]); + if( rc==SQLITE_OK ){ + sqlite3ValueApplyAffinity(pVal, affinity, ENC(db)); + } + pVal->db = pParse->db; + } + } + }else{ + rc = valueFromExpr(db, pExpr, ENC(db), affinity, &pVal, pAlloc); + } + + assert( pVal==0 || pVal->db==db ); + *ppVal = pVal; + return rc; +} + /* ** This function is used to allocate and populate UnpackedRecord ** structures intended to be compared against sample index keys stored @@ -61246,50 +62072,88 @@ SQLITE_PRIVATE int sqlite3Stat4ProbeSetValue( int iVal, /* Array element to populate */ int *pbOk /* OUT: True if value was extracted */ ){ - int rc = SQLITE_OK; + int rc; sqlite3_value *pVal = 0; - sqlite3 *db = pParse->db; - - struct ValueNewStat4Ctx alloc; + alloc.pParse = pParse; alloc.pIdx = pIdx; alloc.ppRec = ppRec; alloc.iVal = iVal; - /* Skip over any TK_COLLATE nodes */ - pExpr = sqlite3ExprSkipCollate(pExpr); - - if( !pExpr ){ - pVal = valueNew(db, &alloc); - if( pVal ){ - sqlite3VdbeMemSetNull((Mem*)pVal); - } - }else if( pExpr->op==TK_VARIABLE - || NEVER(pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE) - ){ - Vdbe *v; - int iBindVar = pExpr->iColumn; - sqlite3VdbeSetVarmask(pParse->pVdbe, iBindVar); - if( (v = pParse->pReprepare)!=0 ){ - pVal = valueNew(db, &alloc); - if( pVal ){ - rc = sqlite3VdbeMemCopy((Mem*)pVal, &v->aVar[iBindVar-1]); - if( rc==SQLITE_OK ){ - sqlite3ValueApplyAffinity(pVal, affinity, ENC(db)); - } - pVal->db = pParse->db; - } - } - }else{ - rc = valueFromExpr(db, pExpr, ENC(db), affinity, &pVal, &alloc); - } + rc = stat4ValueFromExpr(pParse, pExpr, affinity, &alloc, &pVal); + assert( pVal==0 || pVal->db==pParse->db ); *pbOk = (pVal!=0); - - assert( pVal==0 || pVal->db==db ); return rc; } +/* +** Attempt to extract a value from expression pExpr using the methods +** as described for sqlite3Stat4ProbeSetValue() above. +** +** If successful, set *ppVal to point to a new value object and return +** SQLITE_OK. If no value can be extracted, but no other error occurs +** (e.g. OOM), return SQLITE_OK and set *ppVal to NULL. Or, if an error +** does occur, return an SQLite error code. The final value of *ppVal +** is undefined in this case. +*/ +SQLITE_PRIVATE int sqlite3Stat4ValueFromExpr( + Parse *pParse, /* Parse context */ + Expr *pExpr, /* The expression to extract a value from */ + u8 affinity, /* Affinity to use */ + sqlite3_value **ppVal /* OUT: New value object (or NULL) */ +){ + return stat4ValueFromExpr(pParse, pExpr, affinity, 0, ppVal); +} + +/* +** Extract the iCol-th column from the nRec-byte record in pRec. Write +** the column value into *ppVal. If *ppVal is initially NULL then a new +** sqlite3_value object is allocated. +** +** If *ppVal is initially NULL then the caller is responsible for +** ensuring that the value written into *ppVal is eventually freed. +*/ +SQLITE_PRIVATE int sqlite3Stat4Column( + sqlite3 *db, /* Database handle */ + const void *pRec, /* Pointer to buffer containing record */ + int nRec, /* Size of buffer pRec in bytes */ + int iCol, /* Column to extract */ + sqlite3_value **ppVal /* OUT: Extracted value */ +){ + u32 t; /* a column type code */ + int nHdr; /* Size of the header in the record */ + int iHdr; /* Next unread header byte */ + int iField; /* Next unread data byte */ + int szField; /* Size of the current data field */ + int i; /* Column index */ + u8 *a = (u8*)pRec; /* Typecast byte array */ + Mem *pMem = *ppVal; /* Write result into this Mem object */ + + assert( iCol>0 ); + iHdr = getVarint32(a, nHdr); + if( nHdr>nRec || iHdr>=nHdr ) return SQLITE_CORRUPT_BKPT; + iField = nHdr; + for(i=0; i<=iCol; i++){ + iHdr += getVarint32(&a[iHdr], t); + testcase( iHdr==nHdr ); + testcase( iHdr==nHdr+1 ); + if( iHdr>nHdr ) return SQLITE_CORRUPT_BKPT; + szField = sqlite3VdbeSerialTypeLen(t); + iField += szField; + } + testcase( iField==nRec ); + testcase( iField==nRec+1 ); + if( iField>nRec ) return SQLITE_CORRUPT_BKPT; + if( pMem==0 ){ + pMem = *ppVal = sqlite3ValueNew(db); + if( pMem==0 ) return SQLITE_NOMEM; + } + sqlite3VdbeSerialGet(&a[iField-szField], t, pMem); + pMem->enc = ENC(db); + return SQLITE_OK; +} + /* ** Unless it is NULL, the argument must be an UnpackedRecord object returned ** by an earlier call to sqlite3Stat4ProbeSetValue(). This call deletes @@ -61434,18 +62298,35 @@ SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){ } /* -** Resize the Vdbe.aOp array so that it is at least one op larger than -** it was. +** Resize the Vdbe.aOp array so that it is at least nOp elements larger +** than its current size. nOp is guaranteed to be less than or equal +** to 1024/sizeof(Op). ** ** If an out-of-memory error occurs while resizing the array, return -** SQLITE_NOMEM. In this case Vdbe.aOp and Vdbe.nOpAlloc remain +** SQLITE_NOMEM. In this case Vdbe.aOp and Parse.nOpAlloc remain ** unchanged (this is so that any opcodes already allocated can be ** correctly deallocated along with the rest of the Vdbe). */ -static int growOpArray(Vdbe *v){ +static int growOpArray(Vdbe *v, int nOp){ VdbeOp *pNew; Parse *p = v->pParse; + + /* The SQLITE_TEST_REALLOC_STRESS compile-time option is designed to force + ** more frequent reallocs and hence provide more opportunities for + ** simulated OOM faults. SQLITE_TEST_REALLOC_STRESS is generally used + ** during testing only. With SQLITE_TEST_REALLOC_STRESS grow the op array + ** by the minimum* amount required until the size reaches 512. Normal + ** operation (without SQLITE_TEST_REALLOC_STRESS) is to double the current + ** size of the op array or add 1KB of space, whichever is smaller. */ +#ifdef SQLITE_TEST_REALLOC_STRESS + int nNew = (p->nOpAlloc>=512 ? p->nOpAlloc*2 : p->nOpAlloc+nOp); +#else int nNew = (p->nOpAlloc ? p->nOpAlloc*2 : (int)(1024/sizeof(Op))); + UNUSED_PARAMETER(nOp); +#endif + + assert( nOp<=(1024/sizeof(Op)) ); + assert( nNew>=(p->nOpAlloc+nOp) ); pNew = sqlite3DbRealloc(p->db, v->aOp, nNew*sizeof(Op)); if( pNew ){ p->nOpAlloc = sqlite3DbMallocSize(p->db, pNew)/sizeof(Op); @@ -61489,7 +62370,7 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){ assert( p->magic==VDBE_MAGIC_INIT ); assert( op>0 && op<0xff ); if( p->pParse->nOpAlloc<=i ){ - if( growOpArray(p) ){ + if( growOpArray(p, 1) ){ return 1; } } @@ -61626,7 +62507,7 @@ SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){ int j = -1-x; assert( v->magic==VDBE_MAGIC_INIT ); assert( jnLabel ); - if( j>=0 && p->aLabel ){ + if( ALWAYS(j>=0) && p->aLabel ){ p->aLabel[j] = v->nOp; } p->iFixedOp = v->nOp - 1; @@ -61849,7 +62730,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ pParse->aLabel = 0; pParse->nLabel = 0; *pMaxFuncArgs = nMaxArgs; - assert( p->bIsReader!=0 || p->btreeMask==0 ); + assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) ); } /* @@ -61876,7 +62757,7 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg) assert( aOp && !p->db->mallocFailed ); /* Check that sqlite3VdbeUsesBtree() was not called on this VM */ - assert( p->btreeMask==0 ); + assert( DbMaskAllZero(p->btreeMask) ); resolveP2Values(p, pnMaxArg); *pnOp = p->nOp; @@ -61891,7 +62772,7 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg) SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, int iLineno){ int addr; assert( p->magic==VDBE_MAGIC_INIT ); - if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p) ){ + if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p, nOp) ){ return 0; } addr = p->nOp; @@ -62076,7 +62957,7 @@ SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *pVdbe, SubProgram *p){ ** Change the opcode at addr into OP_Noop */ SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){ - if( p->aOp ){ + if( addrnOp ){ VdbeOp *pOp = &p->aOp[addr]; sqlite3 *db = p->db; freeP4(db, pOp->p4type, pOp->p4.p); @@ -62133,7 +63014,9 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int addr = p->nOp - 1; } pOp = &p->aOp[addr]; - assert( pOp->p4type==P4_NOTUSED || pOp->p4type==P4_INT32 ); + assert( pOp->p4type==P4_NOTUSED + || pOp->p4type==P4_INT32 + || pOp->p4type==P4_KEYINFO ); freeP4(db, pOp->p4type, pOp->p4.p); pOp->p4.p = 0; if( n==P4_INT32 ){ @@ -62459,9 +63342,9 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){ assert( i>=0 && idb->nDb && i<(int)sizeof(yDbMask)*8 ); assert( i<(int)sizeof(p->btreeMask)*8 ); - p->btreeMask |= ((yDbMask)1)<btreeMask, i); if( i!=1 && sqlite3BtreeSharable(p->db->aDb[i].pBt) ){ - p->lockMask |= ((yDbMask)1)<lockMask, i); } } @@ -62489,16 +63372,15 @@ SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){ */ SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe *p){ int i; - yDbMask mask; sqlite3 *db; Db *aDb; int nDb; - if( p->lockMask==0 ) return; /* The common case */ + if( DbMaskAllZero(p->lockMask) ) return; /* The common case */ db = p->db; aDb = db->aDb; nDb = db->nDb; - for(i=0, mask=1; ilockMask)!=0 && ALWAYS(aDb[i].pBt!=0) ){ + for(i=0; ilockMask,i) && ALWAYS(aDb[i].pBt!=0) ){ sqlite3BtreeEnter(aDb[i].pBt); } } @@ -62511,16 +63393,15 @@ SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe *p){ */ SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe *p){ int i; - yDbMask mask; sqlite3 *db; Db *aDb; int nDb; - if( p->lockMask==0 ) return; /* The common case */ + if( DbMaskAllZero(p->lockMask) ) return; /* The common case */ db = p->db; aDb = db->aDb; nDb = db->nDb; - for(i=0, mask=1; ilockMask)!=0 && ALWAYS(aDb[i].pBt!=0) ){ + for(i=0; ilockMask,i) && ALWAYS(aDb[i].pBt!=0) ){ sqlite3BtreeLeave(aDb[i].pBt); } } @@ -63491,7 +64372,7 @@ static void checkActiveVdbeCnt(sqlite3 *db){ int nRead = 0; p = db->pVdbe; while( p ){ - if( p->magic==VDBE_MAGIC_RUN && p->pc>=0 ){ + if( sqlite3_stmt_busy((sqlite3_stmt*)p) ){ cnt++; if( p->readOnly==0 ) nWrite++; if( p->bIsReader ) nRead++; @@ -63651,7 +64532,6 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ /* Check for one of the special errors */ mrc = p->rc & 0xff; - assert( p->rc!=SQLITE_IOERR_BLOCKED ); /* This error no longer exists */ isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR || mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL; if( isSpecialError ){ @@ -64083,7 +64963,7 @@ SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor *p){ if( rc ) return rc; if( hasMoved ){ p->cacheStatus = CACHE_STALE; - p->nullRow = 1; + if( hasMoved==2 ) p->nullRow = 1; } } return SQLITE_OK; @@ -64136,7 +65016,7 @@ SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor *p){ */ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){ int flags = pMem->flags; - int n; + u32 n; if( flags&MEM_Null ){ return 0; @@ -64166,11 +65046,11 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){ return 7; } assert( pMem->db->mallocFailed || flags&(MEM_Str|MEM_Blob) ); - n = pMem->n; + assert( pMem->n>=0 ); + n = (u32)pMem->n; if( flags & MEM_Zero ){ n += pMem->u.nZero; } - assert( n>=0 ); return ((n*2) + 12 + ((flags&MEM_Str)!=0)); } @@ -64753,10 +65633,13 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){ ** Key1 and Key2 do not have to contain the same number of fields. If all ** fields that appear in both keys are equal, then pPKey2->default_rc is ** returned. +** +** If database corruption is discovered, set pPKey2->isCorrupt to non-zero +** and return 0. */ SQLITE_PRIVATE int sqlite3VdbeRecordCompare( int nKey1, const void *pKey1, /* Left key */ - const UnpackedRecord *pPKey2, /* Right key */ + UnpackedRecord *pPKey2, /* Right key */ int bSkip /* If true, skip the first field */ ){ u32 d1; /* Offset into aKey[] of next data element */ @@ -64782,6 +65665,10 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare( }else{ idx1 = getVarint32(aKey1, szHdr1); d1 = szHdr1; + if( d1>(unsigned)nKey1 ){ + pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT; + return 0; /* Corruption */ + } i = 0; } @@ -64858,7 +65745,8 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare( testcase( (d1+mem1.n)==(unsigned)nKey1 ); testcase( (d1+mem1.n+1)==(unsigned)nKey1 ); if( (d1+mem1.n) > (unsigned)nKey1 ){ - rc = 1; /* Corruption */ + pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT; + return 0; /* Corruption */ }else if( pKeyInfo->aColl[i] ){ mem1.enc = pKeyInfo->enc; mem1.db = pKeyInfo->db; @@ -64884,7 +65772,8 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare( testcase( (d1+nStr)==(unsigned)nKey1 ); testcase( (d1+nStr+1)==(unsigned)nKey1 ); if( (d1+nStr) > (unsigned)nKey1 ){ - rc = 1; /* Corruption */ + pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT; + return 0; /* Corruption */ }else{ int nCmp = MIN(nStr, pRhs->n); rc = memcmp(&aKey1[d1], pRhs->z, nCmp); @@ -64928,6 +65817,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare( ** value. */ assert( CORRUPT_DB || pPKey2->default_rc==vdbeRecordCompareDebug(nKey1, pKey1, pPKey2) + || pKeyInfo->db->mallocFailed ); return pPKey2->default_rc; } @@ -64937,10 +65827,13 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare( ** that (a) the first field of pPKey2 is an integer, and (b) the ** size-of-header varint at the start of (pKey1/nKey1) fits in a single ** byte (i.e. is less than 128). +** +** To avoid concerns about buffer overreads, this routine is only used +** on schemas where the maximum valid header size is 63 bytes or less. */ static int vdbeRecordCompareInt( int nKey1, const void *pKey1, /* Left key */ - const UnpackedRecord *pPKey2, /* Right key */ + UnpackedRecord *pPKey2, /* Right key */ int bSkip /* Ignored */ ){ const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F]; @@ -64953,6 +65846,7 @@ static int vdbeRecordCompareInt( UNUSED_PARAMETER(bSkip); assert( bSkip==0 ); + assert( (*(u8*)pKey1)<=0x3F || CORRUPT_DB ); switch( serial_type ){ case 1: { /* 1-byte signed integer */ lhs = ONE_BYTE_INT(aKey); @@ -65037,7 +65931,7 @@ static int vdbeRecordCompareInt( */ static int vdbeRecordCompareString( int nKey1, const void *pKey1, /* Left key */ - const UnpackedRecord *pPKey2, /* Right key */ + UnpackedRecord *pPKey2, /* Right key */ int bSkip ){ const u8 *aKey1 = (const u8*)pKey1; @@ -65058,7 +65952,10 @@ static int vdbeRecordCompareString( int szHdr = aKey1[0]; nStr = (serial_type-12) / 2; - if( (szHdr + nStr) > nKey1 ) return 0; /* Corruption */ + if( (szHdr + nStr) > nKey1 ){ + pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT; + return 0; /* Corruption */ + } nCmp = MIN( pPKey2->aMem[0].n, nStr ); res = memcmp(&aKey1[szHdr], pPKey2->aMem[0].z, nCmp); @@ -65086,6 +65983,7 @@ static int vdbeRecordCompareString( || (res<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0) || (res>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0) || CORRUPT_DB + || pPKey2->pKeyInfo->db->mallocFailed ); return res; } @@ -65223,7 +66121,7 @@ idx_rowid_corruption: */ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare( VdbeCursor *pC, /* The cursor to compare against */ - const UnpackedRecord *pUnpacked, /* Unpacked version of key */ + UnpackedRecord *pUnpacked, /* Unpacked version of key */ int *res /* Write the comparison result here */ ){ i64 nCellKey = 0; @@ -66670,7 +67568,7 @@ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){ */ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt *pStmt){ Vdbe *v = (Vdbe*)pStmt; - return v!=0 && v->pc>0 && v->magic==VDBE_MAGIC_RUN; + return v!=0 && v->pc>=0 && v->magic==VDBE_MAGIC_RUN; } /* @@ -67120,6 +68018,12 @@ SQLITE_API int sqlite3_found_count = 0; ** branch can go. It is usually 2. "I" is the direction the branch ** goes. 0 means falls through. 1 means branch is taken. 2 means the ** second alternative branch is taken. +** +** iSrcLine is the source code line (from the __LINE__ macro) that +** generated the VDBE instruction. This instrumentation assumes that all +** source code is in a single file (the amalgamation). Special values 1 +** and 2 for the iSrcLine parameter mean that this particular branch is +** always taken or never taken, respectively. */ #if !defined(SQLITE_VDBE_COVERAGE) # define VdbeBranchTaken(I,M) @@ -67228,21 +68132,21 @@ static VdbeCursor *allocateCursor( ** look like a number, leave it alone. */ static void applyNumericAffinity(Mem *pRec){ - if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){ - double rValue; - i64 iValue; - u8 enc = pRec->enc; - if( (pRec->flags&MEM_Str)==0 ) return; - if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return; - if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){ - pRec->u.i = iValue; - pRec->flags |= MEM_Int; - }else{ - pRec->r = rValue; - pRec->flags |= MEM_Real; - } + double rValue; + i64 iValue; + u8 enc = pRec->enc; + if( (pRec->flags&MEM_Str)==0 ) return; + if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return; + if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){ + pRec->u.i = iValue; + pRec->flags |= MEM_Int; + }else{ + pRec->r = rValue; + pRec->flags |= MEM_Real; } } +#define ApplyNumericAffinity(X) \ + if(((X)->flags&(MEM_Real|MEM_Int))==0){applyNumericAffinity(X);} /* ** Processing is determine by the affinity parameter: @@ -67279,7 +68183,7 @@ static void applyAffinity( }else if( affinity!=SQLITE_AFF_NONE ){ assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL || affinity==SQLITE_AFF_NUMERIC ); - applyNumericAffinity(pRec); + ApplyNumericAffinity(pRec); if( pRec->flags & MEM_Real ){ sqlite3VdbeIntegerAffinity(pRec); } @@ -67314,6 +68218,29 @@ SQLITE_PRIVATE void sqlite3ValueApplyAffinity( applyAffinity((Mem *)pVal, affinity, enc); } +/* +** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or +** none. +** +** Unlike applyNumericAffinity(), this routine does not modify pMem->flags. +** But it does set pMem->r and pMem->u.i appropriately. +*/ +static u16 numericType(Mem *pMem){ + if( pMem->flags & (MEM_Int|MEM_Real) ){ + return pMem->flags & (MEM_Int|MEM_Real); + } + if( pMem->flags & (MEM_Str|MEM_Blob) ){ + if( sqlite3AtoF(pMem->z, &pMem->r, pMem->n, pMem->enc)==0 ){ + return 0; + } + if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){ + return MEM_Int; + } + return MEM_Real; + } + return 0; +} + #ifdef SQLITE_DEBUG /* ** Write a nice string representation of the contents of cell pMem @@ -67837,12 +68764,14 @@ case OP_Return: { /* in1 */ /* Opcode: InitCoroutine P1 P2 P3 * * ** -** Set up register P1 so that it will OP_Yield to the co-routine +** Set up register P1 so that it will Yield to the coroutine ** located at address P3. ** -** If P2!=0 then the co-routine implementation immediately follows -** this opcode. So jump over the co-routine implementation to +** If P2!=0 then the coroutine implementation immediately follows +** this opcode. So jump over the coroutine implementation to ** address P2. +** +** See also: EndCoroutine */ case OP_InitCoroutine: { /* jump */ assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) ); @@ -67858,9 +68787,11 @@ case OP_InitCoroutine: { /* jump */ /* Opcode: EndCoroutine P1 * * * * ** -** The instruction at the address in register P1 is an OP_Yield. -** Jump to the P2 parameter of that OP_Yield. +** The instruction at the address in register P1 is a Yield. +** Jump to the P2 parameter of that Yield. ** After the jump, register P1 becomes undefined. +** +** See also: InitCoroutine */ case OP_EndCoroutine: { /* in1 */ VdbeOp *pCaller; @@ -67877,11 +68808,16 @@ case OP_EndCoroutine: { /* in1 */ /* Opcode: Yield P1 P2 * * * ** -** Swap the program counter with the value in register P1. +** Swap the program counter with the value in register P1. This +** has the effect of yielding to a coroutine. ** -** If the co-routine ends with OP_Yield or OP_Return then continue -** to the next instruction. But if the co-routine ends with -** OP_EndCoroutine, jump immediately to P2. +** If the coroutine that is launched by this instruction ends with +** Yield or Return then continue to the next instruction. But if +** the coroutine launched by this instruction ends with +** EndCoroutine, then jump to P2 rather than continuing with the +** next instruction. +** +** See also: InitCoroutine */ case OP_Yield: { /* in1, jump */ int pcDest; @@ -68044,7 +68980,7 @@ case OP_Real: { /* same as TK_FLOAT, out2-prerelease */ ** Synopsis: r[P2]='P4' ** ** P4 points to a nul terminated UTF-8 string. This opcode is transformed -** into an OP_String before it is executed for the first time. During +** into a String before it is executed for the first time. During ** this transformation, the length of string P4 is computed and stored ** as the P1 parameter. */ @@ -68173,10 +69109,11 @@ case OP_Variable: { /* out2-prerelease */ /* Opcode: Move P1 P2 P3 * * ** Synopsis: r[P2@P3]=r[P1@P3] ** -** Move the values in register P1..P1+P3 over into -** registers P2..P2+P3. Registers P1..P1+P3 are +** Move the P3 values in register P1..P1+P3-1 over into +** registers P2..P2+P3-1. Registers P1..P1+P3-1 are ** left holding a NULL. It is an error for register ranges -** P1..P1+P3 and P2..P2+P3 to overlap. +** P1..P1+P3-1 and P2..P2+P3-1 to overlap. It is an error +** for P3 to be less than 1. */ case OP_Move: { char *zMalloc; /* Holding variable for allocated memory */ @@ -68187,7 +69124,7 @@ case OP_Move: { n = pOp->p3; p1 = pOp->p1; p2 = pOp->p2; - assert( n>=0 && p1>0 && p2>0 ); + assert( n>0 && p1>0 && p2>0 ); assert( p1+n<=p2 || p2+n<=p1 ); pIn1 = &aMem[p1]; @@ -68211,7 +69148,7 @@ case OP_Move: { REGISTER_TRACE(p2++, pOut); pIn1++; pOut++; - }while( n-- ); + }while( --n ); break; } @@ -68443,20 +69380,22 @@ case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */ case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ char bIntint; /* Started out as two integer operands */ - int flags; /* Combined MEM_* flags from both inputs */ + u16 flags; /* Combined MEM_* flags from both inputs */ + u16 type1; /* Numeric type of left operand */ + u16 type2; /* Numeric type of right operand */ i64 iA; /* Integer value of left operand */ i64 iB; /* Integer value of right operand */ double rA; /* Real value of left operand */ double rB; /* Real value of right operand */ pIn1 = &aMem[pOp->p1]; - applyNumericAffinity(pIn1); + type1 = numericType(pIn1); pIn2 = &aMem[pOp->p2]; - applyNumericAffinity(pIn2); + type2 = numericType(pIn2); pOut = &aMem[pOp->p3]; flags = pIn1->flags | pIn2->flags; if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null; - if( (pIn1->flags & pIn2->flags & MEM_Int)==MEM_Int ){ + if( (type1 & type2 & MEM_Int)!=0 ){ iA = pIn1->u.i; iB = pIn2->u.i; bIntint = 1; @@ -68512,7 +69451,7 @@ fp_math: } pOut->r = rB; MemSetTypeFlag(pOut, MEM_Real); - if( (flags & MEM_Real)==0 && !bIntint ){ + if( ((type1|type2)&MEM_Real)==0 && !bIntint ){ sqlite3VdbeIntegerAffinity(pOut); } #endif @@ -69088,6 +70027,7 @@ case OP_Permutation: { } /* Opcode: Compare P1 P2 P3 P4 P5 +** Synopsis: r[P1@P3] <-> r[P2@P3] ** ** Compare two vectors of registers in reg(P1)..reg(P1+P3-1) (call this ** vector "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of @@ -69262,10 +70202,14 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ /* Opcode: Once P1 P2 * * * ** -** Check if OP_Once flag P1 is set. If so, jump to instruction P2. Otherwise, -** set the flag and fall through to the next instruction. In other words, -** this opcode causes all following opcodes up through P2 (but not including -** P2) to run just once and to be skipped on subsequent times through the loop. +** Check the "once" flag number P1. If it is set, jump to instruction P2. +** Otherwise, set the flag and fall through to the next instruction. +** In other words, this opcode causes all following opcodes up through P2 +** (but not including P2) to run just once and to be skipped on subsequent +** times through the loop. +** +** All "once" flags are initially cleared whenever a prepared statement +** first begins to run. */ case OP_Once: { /* jump */ assert( pOp->p1nOnceFlag ); @@ -69282,13 +70226,13 @@ case OP_Once: { /* jump */ ** ** Jump to P2 if the value in register P1 is true. The value ** is considered true if it is numeric and non-zero. If the value -** in P1 is NULL then take the jump if P3 is non-zero. +** in P1 is NULL then take the jump if and only if P3 is non-zero. */ /* Opcode: IfNot P1 P2 P3 * * ** ** Jump to P2 if the value in register P1 is False. The value ** is considered false if it has a numeric value of zero. If the value -** in P1 is NULL then take the jump if P3 is zero. +** in P1 is NULL then take the jump if and only if P3 is non-zero. */ case OP_If: /* jump, in1 */ case OP_IfNot: { /* jump, in1 */ @@ -70100,7 +71044,7 @@ case OP_Transaction: { assert( p->bIsReader ); assert( p->readOnly==0 || pOp->p2==0 ); assert( pOp->p1>=0 && pOp->p1nDb ); - assert( (p->btreeMask & (((yDbMask)1)<p1))!=0 ); + assert( DbMaskTest(p->btreeMask, pOp->p1) ); if( pOp->p2 && (db->flags & SQLITE_QueryOnly)!=0 ){ rc = SQLITE_READONLY; goto abort_due_to_error; @@ -70195,7 +71139,7 @@ case OP_ReadCookie: { /* out2-prerelease */ assert( pOp->p3=0 && iDbnDb ); assert( db->aDb[iDb].pBt!=0 ); - assert( (p->btreeMask & (((yDbMask)1)<btreeMask, iDb) ); sqlite3BtreeGetMeta(db->aDb[iDb].pBt, iCookie, (u32 *)&iMeta); pOut->u.i = iMeta; @@ -70216,7 +71160,7 @@ case OP_SetCookie: { /* in3 */ Db *pDb; assert( pOp->p2p1>=0 && pOp->p1nDb ); - assert( (p->btreeMask & (((yDbMask)1)<p1))!=0 ); + assert( DbMaskTest(p->btreeMask, pOp->p1) ); assert( p->readOnly==0 ); pDb = &db->aDb[pOp->p1]; assert( pDb->pBt!=0 ); @@ -70271,7 +71215,21 @@ case OP_SetCookie: { /* in3 */ ** sequence of the index being opened. Otherwise, if P4 is an integer ** value, it is set to the number of columns in the table. ** -** See also OpenWrite. +** See also: OpenWrite, ReopenIdx +*/ +/* Opcode: ReopenIdx P1 P2 P3 P4 P5 +** Synopsis: root=P2 iDb=P3 +** +** The ReopenIdx opcode works exactly like ReadOpen except that it first +** checks to see if the cursor on P1 is already open with a root page +** number of P2 and if it is this opcode becomes a no-op. In other words, +** if the cursor is already open, do not reopen it. +** +** The ReopenIdx opcode may only be used with P5==0 and with P4 being +** a P4_KEYINFO object. Furthermore, the P3 value must be the same as +** every other ReopenIdx or OpenRead for the same cursor number. +** +** See the OpenRead opcode documentation for additional information. */ /* Opcode: OpenWrite P1 P2 P3 P4 P5 ** Synopsis: root=P2 iDb=P3 @@ -70293,6 +71251,19 @@ case OP_SetCookie: { /* in3 */ ** ** See also OpenRead. */ +case OP_ReopenIdx: { + VdbeCursor *pCur; + + assert( pOp->p5==0 ); + assert( pOp->p4type==P4_KEYINFO ); + pCur = p->apCsr[pOp->p1]; + if( pCur && pCur->pgnoRoot==(u32)pOp->p2 ){ + assert( pCur->iDb==pOp->p3 ); /* Guaranteed by the code generator */ + break; + } + /* If the cursor is not currently open or is open on a different + ** index, then fall through into OP_OpenRead to force a reopen */ +} case OP_OpenRead: case OP_OpenWrite: { int nField; @@ -70307,7 +71278,8 @@ case OP_OpenWrite: { assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR))==pOp->p5 ); assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 ); assert( p->bIsReader ); - assert( pOp->opcode==OP_OpenRead || p->readOnly==0 ); + assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx + || p->readOnly==0 ); if( p->expired ){ rc = SQLITE_ABORT; @@ -70319,7 +71291,7 @@ case OP_OpenWrite: { p2 = pOp->p2; iDb = pOp->p3; assert( iDb>=0 && iDbnDb ); - assert( (p->btreeMask & (((yDbMask)1)<btreeMask, iDb) ); pDb = &db->aDb[iDb]; pX = pDb->pBt; assert( pX!=0 ); @@ -70364,6 +71336,7 @@ case OP_OpenWrite: { if( pCur==0 ) goto no_mem; pCur->nullRow = 1; pCur->isOrdered = 1; + pCur->pgnoRoot = p2; rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor); pCur->pKeyInfo = pKeyInfo; assert( OPFLAG_BULKCSR==BTREE_BULKLOAD ); @@ -70423,6 +71396,7 @@ case OP_OpenEphemeral: { pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1); if( pCx==0 ) goto no_mem; pCx->nullRow = 1; + pCx->isEphemeral = 1; rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt, BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags); if( rc==SQLITE_OK ){ @@ -70517,7 +71491,7 @@ case OP_Close: { break; } -/* Opcode: SeekGe P1 P2 P3 P4 * +/* Opcode: SeekGE P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), @@ -70529,9 +71503,13 @@ case OP_Close: { ** is greater than or equal to the key value. If there are no records ** greater than or equal to the key and P2 is not zero, then jump to P2. ** -** See also: Found, NotFound, Distinct, SeekLt, SeekGt, SeekLe +** This opcode leaves the cursor configured to move in forward order, +** from the beginning toward the end. In other words, the cursor is +** configured to use Next, not Prev. +** +** See also: Found, NotFound, SeekLt, SeekGt, SeekLe */ -/* Opcode: SeekGt P1 P2 P3 P4 * +/* Opcode: SeekGT P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), @@ -70543,9 +71521,13 @@ case OP_Close: { ** is greater than the key value. If there are no records greater than ** the key and P2 is not zero, then jump to P2. ** -** See also: Found, NotFound, Distinct, SeekLt, SeekGe, SeekLe +** This opcode leaves the cursor configured to move in forward order, +** from the beginning toward the end. In other words, the cursor is +** configured to use Next, not Prev. +** +** See also: Found, NotFound, SeekLt, SeekGe, SeekLe */ -/* Opcode: SeekLt P1 P2 P3 P4 * +/* Opcode: SeekLT P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), @@ -70557,9 +71539,13 @@ case OP_Close: { ** is less than the key value. If there are no records less than ** the key and P2 is not zero, then jump to P2. ** -** See also: Found, NotFound, Distinct, SeekGt, SeekGe, SeekLe +** This opcode leaves the cursor configured to move in reverse order, +** from the end toward the beginning. In other words, the cursor is +** configured to use Prev, not Next. +** +** See also: Found, NotFound, SeekGt, SeekGe, SeekLe */ -/* Opcode: SeekLe P1 P2 P3 P4 * +/* Opcode: SeekLE P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), @@ -70571,7 +71557,11 @@ case OP_Close: { ** is less than or equal to the key value. If there are no records ** less than or equal to the key and P2 is not zero, then jump to P2. ** -** See also: Found, NotFound, Distinct, SeekGt, SeekGe, SeekLt +** This opcode leaves the cursor configured to move in reverse order, +** from the end toward the beginning. In other words, the cursor is +** configured to use Prev, not Next. +** +** See also: Found, NotFound, SeekGt, SeekGe, SeekLt */ case OP_SeekLT: /* jump, in3 */ case OP_SeekLE: /* jump, in3 */ @@ -70596,12 +71586,15 @@ case OP_SeekGT: { /* jump, in3 */ assert( pC->pCursor!=0 ); oc = pOp->opcode; pC->nullRow = 0; +#ifdef SQLITE_DEBUG + pC->seekOp = pOp->opcode; +#endif if( pC->isTable ){ /* The input value in P3 might be of any type: integer, real, string, ** blob, or NULL. But it needs to be an integer before we can do ** the seek, so covert it. */ pIn3 = &aMem[pOp->p3]; - applyNumericAffinity(pIn3); + ApplyNumericAffinity(pIn3); iKey = sqlite3VdbeIntValue(pIn3); pC->rowidIsValid = 0; @@ -70751,6 +71744,10 @@ case OP_Seek: { /* in2 */ ** is a prefix of any entry in P1 then a jump is made to P2 and ** P1 is left pointing at the matching entry. ** +** This operation leaves the cursor in a state where it can be +** advanced in the forward direction. The Next instruction will work, +** but not the Prev instruction. +** ** See also: NotFound, NoConflict, NotExists. SeekGe */ /* Opcode: NotFound P1 P2 P3 P4 * @@ -70766,6 +71763,10 @@ case OP_Seek: { /* in2 */ ** falls through to the next instruction and P1 is left pointing at the ** matching entry. ** +** This operation leaves the cursor in a state where it cannot be +** advanced in either direction. In other words, the Next and Prev +** opcodes do not work after this operation. +** ** See also: Found, NotExists, NoConflict */ /* Opcode: NoConflict P1 P2 P3 P4 * @@ -70785,6 +71786,10 @@ case OP_Seek: { /* in2 */ ** This opcode is similar to OP_NotFound with the exceptions that the ** branch is always taken if any part of the search key input is NULL. ** +** This operation leaves the cursor in a state where it cannot be +** advanced in either direction. In other words, the Next and Prev +** opcodes do not work after this operation. +** ** See also: NotFound, Found, NotExists */ case OP_NoConflict: /* jump, in3 */ @@ -70807,6 +71812,9 @@ case OP_Found: { /* jump, in3 */ assert( pOp->p4type==P4_INT32 ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); +#ifdef SQLITE_DEBUG + pC->seekOp = pOp->opcode; +#endif pIn3 = &aMem[pOp->p3]; assert( pC->pCursor!=0 ); assert( pC->isTable==0 ); @@ -70878,6 +71886,10 @@ case OP_Found: { /* jump, in3 */ ** The OP_NotFound opcode performs the same operation on index btrees ** (with arbitrary multi-value keys). ** +** This opcode leaves the cursor in a state where it cannot be advanced +** in either direction. In other words, the Next and Prev opcodes will +** not work following this opcode. +** ** See also: Found, NotFound, NoConflict */ case OP_NotExists: { /* jump, in3 */ @@ -70891,6 +71903,9 @@ case OP_NotExists: { /* jump, in3 */ assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); +#ifdef SQLITE_DEBUG + pC->seekOp = 0; +#endif assert( pC->isTable ); assert( pC->pseudoTableReg==0 ); pCrsr = pC->pCursor; @@ -70913,7 +71928,7 @@ case OP_NotExists: { /* jump, in3 */ } /* Opcode: Sequence P1 P2 * * * -** Synopsis: r[P2]=rowid +** Synopsis: r[P2]=cursor[P1].ctr++ ** ** Find the next available sequence number for cursor P1. ** Write the sequence number into register P2. @@ -71193,7 +72208,7 @@ case OP_InsertInt: { ** The cursor will be left pointing at either the next or the previous ** record in the table. If it is left pointing at the next record, then ** the next Next instruction will be a no-op. Hence it is OK to delete -** a record from within an Next loop. +** a record from within a Next loop. ** ** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is ** incremented (otherwise not). @@ -71253,12 +72268,12 @@ case OP_ResetCount: { } /* Opcode: SorterCompare P1 P2 P3 P4 -** Synopsis: if key(P1)!=rtrim(r[P3],P4) goto P2 +** Synopsis: if key(P1)!=trim(r[P3],P4) goto P2 ** ** P1 is a sorter cursor. This instruction compares a prefix of the -** the record blob in register P3 against a prefix of the entry that -** the sorter cursor currently points to. The final P4 fields of both -** the P3 and sorter record are ignored. +** record blob in register P3 against a prefix of the entry that +** the sorter cursor currently points to. Only the first P4 fields +** of r[P3] and the sorter record are compared. ** ** If either P3 or the sorter contains a NULL in one of their significant ** fields (not counting the P4 fields at the end which are ignored) then @@ -71270,14 +72285,14 @@ case OP_ResetCount: { case OP_SorterCompare: { VdbeCursor *pC; int res; - int nIgnore; + int nKeyCol; pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); assert( pOp->p4type==P4_INT32 ); pIn3 = &aMem[pOp->p3]; - nIgnore = pOp->p4.i; - rc = sqlite3VdbeSorterCompare(pC, pIn3, nIgnore, &res); + nKeyCol = pOp->p4.i; + rc = sqlite3VdbeSorterCompare(pC, pIn3, nKeyCol, &res); VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2-1; @@ -71297,6 +72312,7 @@ case OP_SorterData: { pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); rc = sqlite3VdbeSorterRowkey(pC, pOut); + assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) ); break; } @@ -71456,11 +72472,15 @@ case OP_NullRow: { /* Opcode: Last P1 P2 * * * ** -** The next use of the Rowid or Column or Next instruction for P1 +** The next use of the Rowid or Column or Prev instruction for P1 ** will refer to the last entry in the database table or index. ** If the table or index is empty and P2>0, then jump immediately to P2. ** If P2 is 0 or if the table or index is not empty, fall through ** to the following instruction. +** +** This opcode leaves the cursor configured to move in reverse order, +** from the end toward the beginning. In other words, the cursor is +** configured to use Prev, not Next. */ case OP_Last: { /* jump */ VdbeCursor *pC; @@ -71478,6 +72498,9 @@ case OP_Last: { /* jump */ pC->deferredMoveto = 0; pC->rowidIsValid = 0; pC->cacheStatus = CACHE_STALE; +#ifdef SQLITE_DEBUG + pC->seekOp = OP_Last; +#endif if( pOp->p2>0 ){ VdbeBranchTaken(res!=0,2); if( res ) pc = pOp->p2 - 1; @@ -71514,6 +72537,10 @@ case OP_Sort: { /* jump */ ** If the table or index is empty and P2>0, then jump immediately to P2. ** If P2 is 0 or if the table or index is not empty, fall through ** to the following instruction. +** +** This opcode leaves the cursor configured to move in forward order, +** from the beginning toward the end. In other words, the cursor is +** configured to use Next, not Prev. */ case OP_Rewind: { /* jump */ VdbeCursor *pC; @@ -71525,6 +72552,9 @@ case OP_Rewind: { /* jump */ assert( pC!=0 ); assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) ); res = 1; +#ifdef SQLITE_DEBUG + pC->seekOp = OP_Rewind; +#endif if( isSorter(pC) ){ rc = sqlite3VdbeSorterRewind(db, pC, &res); }else{ @@ -71551,6 +72581,10 @@ case OP_Rewind: { /* jump */ ** to the following instruction. But if the cursor advance was successful, ** jump immediately to P2. ** +** The Next opcode is only valid following an SeekGT, SeekGE, or +** OP_Rewind opcode used to position the cursor. Next is not allowed +** to follow SeekLT, SeekLE, or OP_Last. +** ** The P1 cursor must be for a real table, not a pseudo-table. P1 must have ** been opened prior to this opcode or the program will segfault. ** @@ -71569,7 +72603,7 @@ case OP_Rewind: { /* jump */ */ /* Opcode: NextIfOpen P1 P2 P3 P4 P5 ** -** This opcode works just like OP_Next except that if cursor P1 is not +** This opcode works just like Next except that if cursor P1 is not ** open it behaves a no-op. */ /* Opcode: Prev P1 P2 P3 P4 P5 @@ -71579,6 +72613,11 @@ case OP_Rewind: { /* jump */ ** to the following instruction. But if the cursor backup was successful, ** jump immediately to P2. ** +** +** The Prev opcode is only valid following an SeekLT, SeekLE, or +** OP_Last opcode used to position the cursor. Prev is not allowed +** to follow SeekGT, SeekGE, or OP_Rewind. +** ** The P1 cursor must be for a real table, not a pseudo-table. If P1 is ** not open then the behavior is undefined. ** @@ -71595,7 +72634,7 @@ case OP_Rewind: { /* jump */ */ /* Opcode: PrevIfOpen P1 P2 P3 P4 P5 ** -** This opcode works just like OP_Prev except that if cursor P1 is not +** This opcode works just like Prev except that if cursor P1 is not ** open it behaves a no-op. */ case OP_SorterNext: { /* jump */ @@ -71604,6 +72643,7 @@ case OP_SorterNext: { /* jump */ pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); + res = 0; rc = sqlite3VdbeSorterNext(db, pC, &res); goto next_tail; case OP_PrevIfOpen: /* jump */ @@ -71625,6 +72665,16 @@ case OP_Next: /* jump */ assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious ); assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext ); assert( pOp->opcode!=OP_PrevIfOpen || pOp->p4.xAdvance==sqlite3BtreePrevious); + + /* The Next opcode is only used after SeekGT, SeekGE, and Rewind. + ** The Prev opcode is only used after SeekLT, SeekLE, and Last. */ + assert( pOp->opcode!=OP_Next || pOp->opcode!=OP_NextIfOpen + || pC->seekOp==OP_SeekGT || pC->seekOp==OP_SeekGE + || pC->seekOp==OP_Rewind || pC->seekOp==OP_Found); + assert( pOp->opcode!=OP_Prev || pOp->opcode!=OP_PrevIfOpen + || pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE + || pC->seekOp==OP_Last ); + rc = pOp->p4.xAdvance(pC->pCursor, &res); next_tail: pC->cacheStatus = CACHE_STALE; @@ -71907,7 +72957,7 @@ case OP_Destroy: { /* out2-prerelease */ }else{ iDb = pOp->p3; assert( iCnt==1 ); - assert( (p->btreeMask & (((yDbMask)1)<btreeMask, iDb) ); iMoved = 0; /* Not needed. Only to silence a warning. */ rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved); pOut->flags = MEM_Int; @@ -71947,7 +72997,7 @@ case OP_Clear: { nChange = 0; assert( p->readOnly==0 ); - assert( (p->btreeMask & (((yDbMask)1)<p2))!=0 ); + assert( DbMaskTest(p->btreeMask, pOp->p2) ); rc = sqlite3BtreeClearTable( db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0) ); @@ -71962,6 +73012,29 @@ case OP_Clear: { break; } +/* Opcode: ResetSorter P1 * * * * +** +** Delete all contents from the ephemeral table or sorter +** that is open on cursor P1. +** +** This opcode only works for cursors used for sorting and +** opened with OP_OpenEphemeral or OP_SorterOpen. +*/ +case OP_ResetSorter: { + VdbeCursor *pC; + + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + if( pC->pSorter ){ + sqlite3VdbeSorterReset(db, pC->pSorter); + }else{ + assert( pC->isEphemeral ); + rc = sqlite3BtreeClearTableOfCursor(pC->pCursor); + } + break; +} + /* Opcode: CreateTable P1 P2 * * * ** Synopsis: r[P2]=root iDb=P1 ** @@ -71994,7 +73067,7 @@ case OP_CreateTable: { /* out2-prerelease */ pgno = 0; assert( pOp->p1>=0 && pOp->p1nDb ); - assert( (p->btreeMask & (((yDbMask)1)<p1))!=0 ); + assert( DbMaskTest(p->btreeMask, pOp->p1) ); assert( p->readOnly==0 ); pDb = &db->aDb[pOp->p1]; assert( pDb->pBt!=0 ); @@ -72082,7 +73155,8 @@ case OP_LoadAnalysis: { ** ** Remove the internal (in-memory) data structures that describe ** the table named P4 in database P1. This is called after a table -** is dropped in order to keep the internal representation of the +** is dropped from disk (using the Destroy opcode) in order to keep +** the internal representation of the ** schema consistent with what is on disk. */ case OP_DropTable: { @@ -72094,7 +73168,8 @@ case OP_DropTable: { ** ** Remove the internal (in-memory) data structures that describe ** the index named P4 in database P1. This is called after an index -** is dropped in order to keep the internal representation of the +** is dropped from disk (using the Destroy opcode) +** in order to keep the internal representation of the ** schema consistent with what is on disk. */ case OP_DropIndex: { @@ -72106,7 +73181,8 @@ case OP_DropIndex: { ** ** Remove the internal (in-memory) data structures that describe ** the trigger named P4 in database P1. This is called after a trigger -** is dropped in order to keep the internal representation of the +** is dropped from disk (using the Destroy opcode) in order to keep +** the internal representation of the ** schema consistent with what is on disk. */ case OP_DropTrigger: { @@ -72159,7 +73235,7 @@ case OP_IntegrityCk: { } aRoot[j] = 0; assert( pOp->p5nDb ); - assert( (p->btreeMask & (((yDbMask)1)<p5))!=0 ); + assert( DbMaskTest(p->btreeMask, pOp->p5) ); z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot, (int)pnErr->u.i, &nErr); sqlite3DbFree(db, aRoot); @@ -72268,9 +73344,7 @@ case OP_RowSetTest: { /* jump, in1, in3 */ assert( pOp->p4type==P4_INT32 ); assert( iSet==-1 || iSet>=0 ); if( iSet ){ - exists = sqlite3RowSetTest(pIn1->u.pRowSet, - (u8)(iSet>=0 ? iSet & 0xf : 0xff), - pIn3->u.i); + exists = sqlite3RowSetTest(pIn1->u.pRowSet, iSet, pIn3->u.i); VdbeBranchTaken(exists!=0,2); if( exists ){ pc = pOp->p2 - 1; @@ -72523,17 +73597,16 @@ case OP_IfPos: { /* jump, in1 */ break; } -/* Opcode: IfNeg P1 P2 * * * -** Synopsis: if r[P1]<0 goto P2 +/* Opcode: IfNeg P1 P2 P3 * * +** Synopsis: r[P1]+=P3, if r[P1]<0 goto P2 ** -** If the value of register P1 is less than zero, jump to P2. -** -** It is illegal to use this instruction on a register that does -** not contain an integer. An assertion fault will result if you try. +** Register P1 must contain an integer. Add literal P3 to the value in +** register P1 then if the value of register P1 is less than zero, jump to P2. */ case OP_IfNeg: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); + pIn1->u.i += pOp->p3; VdbeBranchTaken(pIn1->u.i<0, 2); if( pIn1->u.i<0 ){ pc = pOp->p2 - 1; @@ -72546,9 +73619,6 @@ case OP_IfNeg: { /* jump, in1 */ ** ** The register P1 must contain an integer. Add literal P3 to the ** value in register P1. If the result is exactly 0, jump to P2. -** -** It is illegal to use this instruction on a register that does -** not contain an integer. An assertion fault will result if you try. */ case OP_IfZero: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; @@ -72821,7 +73891,7 @@ case OP_IncrVacuum: { /* jump */ Btree *pBt; assert( pOp->p1>=0 && pOp->p1nDb ); - assert( (p->btreeMask & (((yDbMask)1)<p1))!=0 ); + assert( DbMaskTest(p->btreeMask, pOp->p1) ); assert( p->readOnly==0 ); pBt = db->aDb[pOp->p1].pBt; rc = sqlite3BtreeIncrVacuum(pBt); @@ -72836,12 +73906,13 @@ case OP_IncrVacuum: { /* jump */ /* Opcode: Expire P1 * * * * ** -** Cause precompiled statements to become expired. An expired statement -** fails with an error code of SQLITE_SCHEMA if it is ever executed -** (via sqlite3_step()). +** Cause precompiled statements to expire. When an expired statement +** is executed using sqlite3_step() it will either automatically +** reprepare itself (if it was originally created using sqlite3_prepare_v2()) +** or it will fail with SQLITE_SCHEMA. ** ** If P1 is 0, then all SQL statements become expired. If P1 is non-zero, -** then only the currently executing statement is affected. +** then only the currently executing statement is expired. */ case OP_Expire: { if( !pOp->p1 ){ @@ -72873,7 +73944,7 @@ case OP_TableLock: { if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommitted) ){ int p1 = pOp->p1; assert( p1>=0 && p1nDb ); - assert( (p->btreeMask & (((yDbMask)1)<btreeMask, p1) ); assert( isWriteLock==0 || isWriteLock==1 ); rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock); if( (rc&0xFF)==SQLITE_LOCKED ){ @@ -72970,7 +74041,7 @@ case OP_VOpen: { #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VFilter P1 P2 P3 P4 * -** Synopsis: iPlan=r[P3] zPlan='P4' +** Synopsis: iplan=r[P3] zplan='P4' ** ** P1 is a cursor opened using VOpen. P2 is an address to jump to if ** the filtered result set is empty. @@ -73323,7 +74394,7 @@ case OP_Init: { /* jump */ if( zTrace ){ int i; for(i=0; inDb; i++){ - if( MASKBIT(i) & p->btreeMask)==0 ) continue; + if( DbMaskTest(p->btreeMask, i)==0 ) continue; sqlite3_file_control(db, db->aDb[i].zName, SQLITE_FCNTL_TRACE, zTrace); } } @@ -73366,8 +74437,8 @@ default: { /* This is really OP_Noop and OP_Explain */ #ifdef VDBE_PROFILE { - u64 elapsed = sqlite3Hwtime() - start; - pOp->cycles += elapsed; + u64 endTime = sqlite3Hwtime(); + if( endTime>start ) pOp->cycles += endTime - start; pOp->cnt++; } #endif @@ -73538,9 +74609,7 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){ p->iOffset = pC->aType[p->iCol + pC->nField]; p->nByte = sqlite3VdbeSerialTypeLen(type); p->pCsr = pC->pCursor; - sqlite3BtreeEnterCursor(p->pCsr); - sqlite3BtreeCacheOverflow(p->pCsr); - sqlite3BtreeLeaveCursor(p->pCsr); + sqlite3BtreeIncrblobCursor(p->pCsr); } } @@ -74280,7 +75349,6 @@ static int vdbeSorterIterInit( rc = sqlite3OsRead( pSorter->pTemp1, &pIter->aBuffer[iBuf], nRead, iStart ); - assert( rc!=SQLITE_IOERR_SHORT_READ ); } if( rc==SQLITE_OK ){ @@ -74316,7 +75384,7 @@ static int vdbeSorterIterInit( */ static void vdbeSorterCompare( const VdbeCursor *pCsr, /* Cursor object (for pKeyInfo) */ - int nIgnore, /* Ignore the last nIgnore fields */ + int nKeyCol, /* Num of columns. 0 means "all" */ const void *pKey1, int nKey1, /* Left side of comparison */ const void *pKey2, int nKey2, /* Right side of comparison */ int *pRes /* OUT: Result of comparison */ @@ -74330,10 +75398,9 @@ static void vdbeSorterCompare( sqlite3VdbeRecordUnpack(pKeyInfo, nKey2, pKey2, r2); } - if( nIgnore ){ - r2->nField = pKeyInfo->nField - nIgnore; - assert( r2->nField>0 ); - for(i=0; inField; i++){ + if( nKeyCol ){ + r2->nField = nKeyCol; + for(i=0; iaMem[i].flags & MEM_Null ){ *pRes = -1; return; @@ -74434,23 +75501,40 @@ static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){ } } +/* +** Reset a sorting cursor back to its original empty state. +*/ +SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){ + if( pSorter->aIter ){ + int i; + for(i=0; inTree; i++){ + vdbeSorterIterZero(db, &pSorter->aIter[i]); + } + sqlite3DbFree(db, pSorter->aIter); + pSorter->aIter = 0; + } + if( pSorter->pTemp1 ){ + sqlite3OsCloseFree(pSorter->pTemp1); + pSorter->pTemp1 = 0; + } + vdbeSorterRecordFree(db, pSorter->pRecord); + pSorter->pRecord = 0; + pSorter->iWriteOff = 0; + pSorter->iReadOff = 0; + pSorter->nInMemory = 0; + pSorter->nTree = 0; + pSorter->nPMA = 0; + pSorter->aTree = 0; +} + + /* ** Free any cursor components allocated by sqlite3VdbeSorterXXX routines. */ SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){ VdbeSorter *pSorter = pCsr->pSorter; if( pSorter ){ - if( pSorter->aIter ){ - int i; - for(i=0; inTree; i++){ - vdbeSorterIterZero(db, &pSorter->aIter[i]); - } - sqlite3DbFree(db, pSorter->aIter); - } - if( pSorter->pTemp1 ){ - sqlite3OsCloseFree(pSorter->pTemp1); - } - vdbeSorterRecordFree(db, pSorter->pRecord); + sqlite3VdbeSorterReset(db, pSorter); sqlite3DbFree(db, pSorter->pUnpacked); sqlite3DbFree(db, pSorter); pCsr->pSorter = 0; @@ -74886,14 +75970,55 @@ SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, in if( pSorter->aTree ){ int iPrev = pSorter->aTree[1];/* Index of iterator to advance */ - int i; /* Index of aTree[] to recalculate */ - rc = vdbeSorterIterNext(db, &pSorter->aIter[iPrev]); - for(i=(pSorter->nTree+iPrev)/2; rc==SQLITE_OK && i>0; i=i/2){ - rc = vdbeSorterDoCompare(pCsr, i); - } + if( rc==SQLITE_OK ){ + int i; /* Index of aTree[] to recalculate */ + VdbeSorterIter *pIter1; /* First iterator to compare */ + VdbeSorterIter *pIter2; /* Second iterator to compare */ + u8 *pKey2; /* To pIter2->aKey, or 0 if record cached */ - *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0); + /* Find the first two iterators to compare. The one that was just + ** advanced (iPrev) and the one next to it in the array. */ + pIter1 = &pSorter->aIter[(iPrev & 0xFFFE)]; + pIter2 = &pSorter->aIter[(iPrev | 0x0001)]; + pKey2 = pIter2->aKey; + + for(i=(pSorter->nTree+iPrev)/2; i>0; i=i/2){ + /* Compare pIter1 and pIter2. Store the result in variable iRes. */ + int iRes; + if( pIter1->pFile==0 ){ + iRes = +1; + }else if( pIter2->pFile==0 ){ + iRes = -1; + }else{ + vdbeSorterCompare(pCsr, 0, + pIter1->aKey, pIter1->nKey, pKey2, pIter2->nKey, &iRes + ); + } + + /* If pIter1 contained the smaller value, set aTree[i] to its index. + ** Then set pIter2 to the next iterator to compare to pIter1. In this + ** case there is no cache of pIter2 in pSorter->pUnpacked, so set + ** pKey2 to point to the record belonging to pIter2. + ** + ** Alternatively, if pIter2 contains the smaller of the two values, + ** set aTree[i] to its index and update pIter1. If vdbeSorterCompare() + ** was actually called above, then pSorter->pUnpacked now contains + ** a value equivalent to pIter2. So set pKey2 to NULL to prevent + ** vdbeSorterCompare() from decoding pIter2 again. */ + if( iRes<=0 ){ + pSorter->aTree[i] = (int)(pIter1 - pSorter->aIter); + pIter2 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ]; + pKey2 = pIter2->aKey; + }else{ + if( pIter1->pFile ) pKey2 = 0; + pSorter->aTree[i] = (int)(pIter2 - pSorter->aIter); + pIter1 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ]; + } + + } + *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0); + } }else{ SorterRecord *pFree = pSorter->pRecord; pSorter->pRecord = pFree->pNext; @@ -74957,14 +76082,14 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){ SQLITE_PRIVATE int sqlite3VdbeSorterCompare( const VdbeCursor *pCsr, /* Sorter cursor */ Mem *pVal, /* Value to compare to current sorter key */ - int nIgnore, /* Ignore this many fields at the end */ + int nKeyCol, /* Only compare this many fields */ int *pRes /* OUT: Result of comparison */ ){ VdbeSorter *pSorter = pCsr->pSorter; void *pKey; int nKey; /* Sorter key to compare pVal with */ pKey = vdbeSorterRowkey(pSorter, &nKey); - vdbeSorterCompare(pCsr, nIgnore, pVal->z, pVal->n, pKey, nKey, pRes); + vdbeSorterCompare(pCsr, nKeyCol, pVal->z, pVal->n, pKey, nKey, pRes); return SQLITE_OK; } @@ -75996,7 +77121,7 @@ static int lookupName( } } if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && HasRowid(pTab) ){ - /* IMP: R-24309-18625 */ + /* IMP: R-51414-32910 */ /* IMP: R-44911-55124 */ iCol = -1; } @@ -76352,8 +77477,13 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ /* EVIDENCE-OF: R-61304-29449 The unlikely(X) function is equivalent to ** likelihood(X, 0.0625). ** EVIDENCE-OF: R-01283-11636 The unlikely(X) function is short-hand for - ** likelihood(X,0.0625). */ - pExpr->iTable = 62; /* TUNING: Default 2nd arg to unlikely() is 0.0625 */ + ** likelihood(X,0.0625). + ** EVIDENCE-OF: R-36850-34127 The likely(X) function is short-hand for + ** likelihood(X,0.9375). + ** EVIDENCE-OF: R-53436-40973 The likely(X) function is equivalent to + ** likelihood(X,0.9375). */ + /* TUNING: unlikely() probability is 0.0625. likely() is 0.9375 */ + pExpr->iTable = pDef->zName[0]=='u' ? 62 : 938; } } } @@ -77129,6 +78259,7 @@ SQLITE_PRIVATE void sqlite3ResolveSelfReference( SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){ int op; pExpr = sqlite3ExprSkipCollate(pExpr); + if( pExpr->flags & EP_Generic ) return 0; op = pExpr->op; if( op==TK_SELECT ){ assert( pExpr->flags&EP_xIsSelect ); @@ -77161,7 +78292,11 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){ ** If a memory allocation error occurs, that fact is recorded in pParse->db ** and the pExpr parameter is returned unchanged. */ -SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr *pExpr, Token *pCollName){ +SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken( + Parse *pParse, /* Parsing context */ + Expr *pExpr, /* Add the "COLLATE" clause to this expression */ + const Token *pCollName /* Name of collating sequence */ +){ if( pCollName->n>0 ){ Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1); if( pNew ){ @@ -77214,6 +78349,7 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ Expr *p = pExpr; while( p ){ int op = p->op; + if( p->flags & EP_Generic ) break; if( op==TK_CAST || op==TK_UPLUS ){ p = p->pLeft; continue; @@ -78045,7 +79181,6 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags) if( p==0 ) return 0; pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) ); if( pNew==0 ) return 0; - pNew->iECursor = 0; pNew->nExpr = i = p->nExpr; if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; inExpr; i+=i){} pNew->a = pItem = sqlite3DbMallocRaw(db, i*sizeof(p->a[0]) ); @@ -78158,7 +79293,6 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){ pNew->selFlags = p->selFlags & ~SF_UsesEphemeral; pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; - pNew->addrOpenEphm[2] = -1; pNew->nSelectRow = p->nSelectRow; pNew->pWith = withDup(db, p->pWith); return pNew; @@ -78460,6 +79594,9 @@ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){ case TK_FLOAT: case TK_BLOB: return 0; + case TK_COLUMN: + assert( p->pTab!=0 ); + return p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0; default: return 1; } @@ -78567,6 +79704,40 @@ SQLITE_PRIVATE int sqlite3CodeOnce(Parse *pParse){ return sqlite3VdbeAddOp1(v, OP_Once, pParse->nOnce++); } +/* +** Generate code that checks the left-most column of index table iCur to see if +** it contains any NULL entries. Cause the register at regHasNull to be set +** to a non-NULL value if iCur contains no NULLs. Cause register regHasNull +** to be set to NULL if iCur contains one or more NULL values. +*/ +static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){ + int j1; + sqlite3VdbeAddOp2(v, OP_Integer, 0, regHasNull); + j1 = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Column, iCur, 0, regHasNull); + sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); + VdbeComment((v, "first_entry_in(%d)", iCur)); + sqlite3VdbeJumpHere(v, j1); +} + + +#ifndef SQLITE_OMIT_SUBQUERY +/* +** The argument is an IN operator with a list (not a subquery) on the +** right-hand side. Return TRUE if that list is constant. +*/ +static int sqlite3InRhsIsConstant(Expr *pIn){ + Expr *pLHS; + int res; + assert( !ExprHasProperty(pIn, EP_xIsSelect) ); + pLHS = pIn->pLeft; + pIn->pLeft = 0; + res = sqlite3ExprIsConstant(pIn); + pIn->pLeft = pLHS; + return res; +} +#endif + /* ** This function is used by the implementation of the IN (...) operator. ** The pX parameter is the expression on the RHS of the IN operator, which @@ -78576,7 +79747,7 @@ SQLITE_PRIVATE int sqlite3CodeOnce(Parse *pParse){ ** be used either to test for membership in the RHS set or to iterate through ** all members of the RHS set, skipping duplicates. ** -** A cursor is opened on the b-tree object that the RHS of the IN operator +** A cursor is opened on the b-tree object that is the RHS of the IN operator ** and pX->iTable is set to the index of that cursor. ** ** The returned value of this function indicates the b-tree type, as follows: @@ -78586,6 +79757,8 @@ SQLITE_PRIVATE int sqlite3CodeOnce(Parse *pParse){ ** IN_INDEX_INDEX_DESC - The cursor was opened on a descending index. ** IN_INDEX_EPH - The cursor was opened on a specially created and ** populated epheremal table. +** IN_INDEX_NOOP - No cursor was allocated. The IN operator must be +** implemented as a sequence of comparisons. ** ** An existing b-tree might be used if the RHS expression pX is a simple ** subquery such as: @@ -78595,51 +79768,56 @@ SQLITE_PRIVATE int sqlite3CodeOnce(Parse *pParse){ ** If the RHS of the IN operator is a list or a more complex subquery, then ** an ephemeral table might need to be generated from the RHS and then ** pX->iTable made to point to the ephermeral table instead of an -** existing table. +** existing table. ** -** If the prNotFound parameter is 0, then the b-tree will be used to iterate -** through the set members, skipping any duplicates. In this case an -** epheremal table must be used unless the selected is guaranteed +** The inFlags parameter must contain exactly one of the bits +** IN_INDEX_MEMBERSHIP or IN_INDEX_LOOP. If inFlags contains +** IN_INDEX_MEMBERSHIP, then the generated table will be used for a +** fast membership test. When the IN_INDEX_LOOP bit is set, the +** IN index will be used to loop over all values of the RHS of the +** IN operator. +** +** When IN_INDEX_LOOP is used (and the b-tree will be used to iterate +** through the set members) then the b-tree must not contain duplicates. +** An epheremal table must be used unless the selected is guaranteed ** to be unique - either because it is an INTEGER PRIMARY KEY or it ** has a UNIQUE constraint or UNIQUE index. ** -** If the prNotFound parameter is not 0, then the b-tree will be used -** for fast set membership tests. In this case an epheremal table must +** When IN_INDEX_MEMBERSHIP is used (and the b-tree will be used +** for fast set membership tests) then an epheremal table must ** be used unless is an INTEGER PRIMARY KEY or an index can ** be found with as its left-most column. ** +** If the IN_INDEX_NOOP_OK and IN_INDEX_MEMBERSHIP are both set and +** if the RHS of the IN operator is a list (not a subquery) then this +** routine might decide that creating an ephemeral b-tree for membership +** testing is too expensive and return IN_INDEX_NOOP. In that case, the +** calling routine should implement the IN operator using a sequence +** of Eq or Ne comparison operations. +** ** When the b-tree is being used for membership tests, the calling function -** needs to know whether or not the structure contains an SQL NULL -** value in order to correctly evaluate expressions like "X IN (Y, Z)". -** If there is any chance that the (...) might contain a NULL value at +** might need to know whether or not the RHS side of the IN operator +** contains a NULL. If prRhsHasNull is not a NULL pointer and +** if there is any chance that the (...) might contain a NULL value at ** runtime, then a register is allocated and the register number written -** to *prNotFound. If there is no chance that the (...) contains a -** NULL value, then *prNotFound is left unchanged. +** to *prRhsHasNull. If there is no chance that the (...) contains a +** NULL value, then *prRhsHasNull is left unchanged. ** -** If a register is allocated and its location stored in *prNotFound, then -** its initial value is NULL. If the (...) does not remain constant -** for the duration of the query (i.e. the SELECT within the (...) -** is a correlated subquery) then the value of the allocated register is -** reset to NULL each time the subquery is rerun. This allows the -** caller to use vdbe code equivalent to the following: -** -** if( register==NULL ){ -** has_null = -** register = 1 -** } -** -** in order to avoid running the -** test more often than is necessary. +** If a register is allocated and its location stored in *prRhsHasNull, then +** the value in that register will be NULL if the b-tree contains one or more +** NULL values, and it will be some non-NULL value if the b-tree contains no +** NULL values. */ #ifndef SQLITE_OMIT_SUBQUERY -SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ +SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){ Select *p; /* SELECT to the right of IN operator */ int eType = 0; /* Type of RHS table. IN_INDEX_* */ int iTab = pParse->nTab++; /* Cursor of the RHS table */ - int mustBeUnique = (prNotFound==0); /* True if RHS must be unique */ + int mustBeUnique; /* True if RHS must be unique */ Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */ assert( pX->op==TK_IN ); + mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0; /* Check to see if an existing table or index can be used to ** satisfy the query. This is preferable to generating a new @@ -78696,7 +79874,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){ if( (pIdx->aiColumn[0]==iCol) && sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq - && (!mustBeUnique || (pIdx->nKeyCol==1 && pIdx->onError!=OE_None)) + && (!mustBeUnique || (pIdx->nKeyCol==1 && IsUniqueIndex(pIdx))) ){ int iAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb); @@ -78705,9 +79883,9 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 ); eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0]; - if( prNotFound && !pTab->aCol[iCol].notNull ){ - *prNotFound = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound); + if( prRhsHasNull && !pTab->aCol[iCol].notNull ){ + *prRhsHasNull = ++pParse->nMem; + sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull); } sqlite3VdbeJumpHere(v, iAddr); } @@ -78715,22 +79893,36 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ } } + /* If no preexisting index is available for the IN clause + ** and IN_INDEX_NOOP is an allowed reply + ** and the RHS of the IN operator is a list, not a subquery + ** and the RHS is not contant or has two or fewer terms, + ** then it is not worth creating an ephermeral table to evaluate + ** the IN operator so return IN_INDEX_NOOP. + */ + if( eType==0 + && (inFlags & IN_INDEX_NOOP_OK) + && !ExprHasProperty(pX, EP_xIsSelect) + && (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2) + ){ + eType = IN_INDEX_NOOP; + } + + if( eType==0 ){ - /* Could not found an existing table or index to use as the RHS b-tree. + /* Could not find an existing table or index to use as the RHS b-tree. ** We will have to generate an ephemeral table to do the job. */ u32 savedNQueryLoop = pParse->nQueryLoop; int rMayHaveNull = 0; eType = IN_INDEX_EPH; - if( prNotFound ){ - *prNotFound = rMayHaveNull = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound); - }else{ - testcase( pParse->nQueryLoop>0 ); + if( inFlags & IN_INDEX_LOOP ){ pParse->nQueryLoop = 0; if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){ eType = IN_INDEX_ROWID; } + }else if( prRhsHasNull ){ + *prRhsHasNull = rMayHaveNull = ++pParse->nMem; } sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID); pParse->nQueryLoop = savedNQueryLoop; @@ -78761,15 +79953,9 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ ** ** If rMayHaveNull is non-zero, that means that the operation is an IN ** (not a SELECT or EXISTS) and that the RHS might contains NULLs. -** Furthermore, the IN is in a WHERE clause and that we really want -** to iterate over the RHS of the IN operator in order to quickly locate -** all corresponding LHS elements. All this routine does is initialize -** the register given by rMayHaveNull to NULL. Calling routines will take -** care of changing this register value to non-NULL if the RHS is NULL-free. -** -** If rMayHaveNull is zero, that means that the subquery is being used -** for membership testing only. There is no need to initialize any -** registers to indicate the presence or absence of NULLs on the RHS. +** All this routine does is initialize the register given by rMayHaveNull +** to NULL. Calling routines will take care of changing this register +** value to non-NULL if the RHS is NULL-free. ** ** For a SELECT or EXISTS operator, return the register that holds the ** result. For IN operators or if an error occurs, the return value is 0. @@ -78778,10 +79964,10 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ SQLITE_PRIVATE int sqlite3CodeSubselect( Parse *pParse, /* Parsing context */ Expr *pExpr, /* The IN, SELECT, or EXISTS operator */ - int rMayHaveNull, /* Register that records whether NULLs exist in RHS */ + int rHasNullFlag, /* Register that records whether NULLs exist in RHS */ int isRowid /* If true, LHS of IN operator is a rowid */ ){ - int testAddr = -1; /* One-time test address */ + int jmpIfDynamic = -1; /* One-time test address */ int rReg = 0; /* Register storing resulting */ Vdbe *v = sqlite3GetVdbe(pParse); if( NEVER(v==0) ) return 0; @@ -78798,13 +79984,13 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( ** save the results, and reuse the same result on subsequent invocations. */ if( !ExprHasProperty(pExpr, EP_VarSelect) ){ - testAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v); + jmpIfDynamic = sqlite3CodeOnce(pParse); VdbeCoverage(v); } #ifndef SQLITE_OMIT_EXPLAIN if( pParse->explain==2 ){ char *zMsg = sqlite3MPrintf( - pParse->db, "EXECUTE %s%s SUBQUERY %d", testAddr>=0?"":"CORRELATED ", + pParse->db, "EXECUTE %s%s SUBQUERY %d", jmpIfDynamic>=0?"":"CORRELATED ", pExpr->op==TK_IN?"LIST":"SCALAR", pParse->iNextSelectId ); sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC); @@ -78818,10 +80004,6 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */ KeyInfo *pKeyInfo = 0; /* Key information */ - if( rMayHaveNull ){ - sqlite3VdbeAddOp2(v, OP_Null, 0, rMayHaveNull); - } - affinity = sqlite3ExprAffinity(pLeft); /* Whether this is an 'x IN(SELECT...)' or an 'x IN()' @@ -78847,6 +80029,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( ** Generate code to write the results of the select into the temporary ** table allocated and opened above. */ + Select *pSelect = pExpr->x.pSelect; SelectDest dest; ExprList *pEList; @@ -78854,13 +80037,15 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable); dest.affSdst = (u8)affinity; assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); - pExpr->x.pSelect->iLimit = 0; + pSelect->iLimit = 0; + testcase( pSelect->selFlags & SF_Distinct ); + pSelect->selFlags &= ~SF_Distinct; testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */ - if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){ + if( sqlite3Select(pParse, pSelect, &dest) ){ sqlite3KeyInfoUnref(pKeyInfo); return 0; } - pEList = pExpr->x.pSelect->pEList; + pEList = pSelect->pEList; assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */ assert( pEList!=0 ); assert( pEList->nExpr>0 ); @@ -78891,7 +80076,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( /* Loop through each expression in . */ r1 = sqlite3GetTempReg(pParse); r2 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp2(v, OP_Null, 0, r2); + if( isRowid ) sqlite3VdbeAddOp2(v, OP_Null, 0, r2); for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){ Expr *pE2 = pItem->pExpr; int iValToIns; @@ -78901,9 +80086,9 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( ** this code only executes once. Because for a non-constant ** expression we need to rerun this code each time. */ - if( testAddr>=0 && !sqlite3ExprIsConstant(pE2) ){ - sqlite3VdbeChangeToNoop(v, testAddr); - testAddr = -1; + if( jmpIfDynamic>=0 && !sqlite3ExprIsConstant(pE2) ){ + sqlite3VdbeChangeToNoop(v, jmpIfDynamic); + jmpIfDynamic = -1; } /* Evaluate the expression and insert it into the temp table */ @@ -78973,10 +80158,14 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( } } - if( testAddr>=0 ){ - sqlite3VdbeJumpHere(v, testAddr); + if( rHasNullFlag ){ + sqlite3SetHasNullFlag(v, pExpr->iTable, rHasNullFlag); } - sqlite3ExprCachePop(pParse, 1); + + if( jmpIfDynamic>=0 ){ + sqlite3VdbeJumpHere(v, jmpIfDynamic); + } + sqlite3ExprCachePop(pParse); return rReg; } @@ -78995,7 +80184,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( ** if the LHS is NULL or if the LHS is not contained within the RHS and the ** RHS contains one or more NULL values. ** -** This routine generates code will jump to destIfFalse if the LHS is not +** This routine generates code that jumps to destIfFalse if the LHS is not ** contained within the RHS. If due to NULLs we cannot determine if the LHS ** is contained in the RHS then jump to destIfNull. If the LHS is contained ** within the RHS then fall through. @@ -79018,7 +80207,9 @@ static void sqlite3ExprCodeIN( v = pParse->pVdbe; assert( v!=0 ); /* OOM detected prior to this routine */ VdbeNoopComment((v, "begin IN expr")); - eType = sqlite3FindInIndex(pParse, pExpr, &rRhsHasNull); + eType = sqlite3FindInIndex(pParse, pExpr, + IN_INDEX_MEMBERSHIP | IN_INDEX_NOOP_OK, + destIfFalse==destIfNull ? 0 : &rRhsHasNull); /* Figure out the affinity to use to create a key from the results ** of the expression. affinityStr stores a static string suitable for @@ -79032,86 +80223,118 @@ static void sqlite3ExprCodeIN( r1 = sqlite3GetTempReg(pParse); sqlite3ExprCode(pParse, pExpr->pLeft, r1); - /* If the LHS is NULL, then the result is either false or NULL depending - ** on whether the RHS is empty or not, respectively. + /* If sqlite3FindInIndex() did not find or create an index that is + ** suitable for evaluating the IN operator, then evaluate using a + ** sequence of comparisons. */ - if( destIfNull==destIfFalse ){ - /* Shortcut for the common case where the false and NULL outcomes are - ** the same. */ - sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v); + if( eType==IN_INDEX_NOOP ){ + ExprList *pList = pExpr->x.pList; + CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); + int labelOk = sqlite3VdbeMakeLabel(v); + int r2, regToFree; + int regCkNull = 0; + int ii; + assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + if( destIfNull!=destIfFalse ){ + regCkNull = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_BitAnd, r1, r1, regCkNull); + } + for(ii=0; iinExpr; ii++){ + r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, ®ToFree); + if( regCkNull && sqlite3ExprCanBeNull(pList->a[ii].pExpr) ){ + sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull); + } + if( iinExpr-1 || destIfNull!=destIfFalse ){ + sqlite3VdbeAddOp4(v, OP_Eq, r1, labelOk, r2, + (void*)pColl, P4_COLLSEQ); + VdbeCoverageIf(v, iinExpr-1); + VdbeCoverageIf(v, ii==pList->nExpr-1); + sqlite3VdbeChangeP5(v, affinity); + }else{ + assert( destIfNull==destIfFalse ); + sqlite3VdbeAddOp4(v, OP_Ne, r1, destIfFalse, r2, + (void*)pColl, P4_COLLSEQ); VdbeCoverage(v); + sqlite3VdbeChangeP5(v, affinity | SQLITE_JUMPIFNULL); + } + sqlite3ReleaseTempReg(pParse, regToFree); + } + if( regCkNull ){ + sqlite3VdbeAddOp2(v, OP_IsNull, regCkNull, destIfNull); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse); + } + sqlite3VdbeResolveLabel(v, labelOk); + sqlite3ReleaseTempReg(pParse, regCkNull); }else{ - int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull); - sqlite3VdbeJumpHere(v, addr1); - } - - if( eType==IN_INDEX_ROWID ){ - /* In this case, the RHS is the ROWID of table b-tree + + /* If the LHS is NULL, then the result is either false or NULL depending + ** on whether the RHS is empty or not, respectively. */ - sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse); VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, destIfFalse, r1); - VdbeCoverage(v); - }else{ - /* In this case, the RHS is an index b-tree. - */ - sqlite3VdbeAddOp4(v, OP_Affinity, r1, 1, 0, &affinity, 1); - - /* If the set membership test fails, then the result of the - ** "x IN (...)" expression must be either 0 or NULL. If the set - ** contains no NULL values, then the result is 0. If the set - ** contains one or more NULL values, then the result of the - ** expression is also NULL. - */ - if( rRhsHasNull==0 || destIfFalse==destIfNull ){ - /* This branch runs if it is known at compile time that the RHS - ** cannot contain NULL values. This happens as the result - ** of a "NOT NULL" constraint in the database schema. - ** - ** Also run this branch if NULL is equivalent to FALSE - ** for this particular IN operator. + if( sqlite3ExprCanBeNull(pExpr->pLeft) ){ + if( destIfNull==destIfFalse ){ + /* Shortcut for the common case where the false and NULL outcomes are + ** the same. */ + sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v); + }else{ + int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull); + sqlite3VdbeJumpHere(v, addr1); + } + } + + if( eType==IN_INDEX_ROWID ){ + /* In this case, the RHS is the ROWID of table b-tree */ - sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse, r1, 1); + sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, destIfFalse, r1); VdbeCoverage(v); }else{ - /* In this branch, the RHS of the IN might contain a NULL and - ** the presence of a NULL on the RHS makes a difference in the - ** outcome. + /* In this case, the RHS is an index b-tree. */ - int j1, j2; - - /* First check to see if the LHS is contained in the RHS. If so, - ** then the presence of NULLs in the RHS does not matter, so jump - ** over all of the code that follows. + sqlite3VdbeAddOp4(v, OP_Affinity, r1, 1, 0, &affinity, 1); + + /* If the set membership test fails, then the result of the + ** "x IN (...)" expression must be either 0 or NULL. If the set + ** contains no NULL values, then the result is 0. If the set + ** contains one or more NULL values, then the result of the + ** expression is also NULL. */ - j1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1); - VdbeCoverage(v); - - /* Here we begin generating code that runs if the LHS is not - ** contained within the RHS. Generate additional code that - ** tests the RHS for NULLs. If the RHS contains a NULL then - ** jump to destIfNull. If there are no NULLs in the RHS then - ** jump to destIfFalse. - */ - sqlite3VdbeAddOp2(v, OP_If, rRhsHasNull, destIfNull); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_IfNot, rRhsHasNull, destIfFalse); VdbeCoverage(v); - j2 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, rRhsHasNull, 1); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Integer, 0, rRhsHasNull); - sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse); - sqlite3VdbeJumpHere(v, j2); - sqlite3VdbeAddOp2(v, OP_Integer, 1, rRhsHasNull); - sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull); - - /* The OP_Found at the top of this branch jumps here when true, - ** causing the overall IN expression evaluation to fall through. - */ - sqlite3VdbeJumpHere(v, j1); + assert( destIfFalse!=destIfNull || rRhsHasNull==0 ); + if( rRhsHasNull==0 ){ + /* This branch runs if it is known at compile time that the RHS + ** cannot contain NULL values. This happens as the result + ** of a "NOT NULL" constraint in the database schema. + ** + ** Also run this branch if NULL is equivalent to FALSE + ** for this particular IN operator. + */ + sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse, r1, 1); + VdbeCoverage(v); + }else{ + /* In this branch, the RHS of the IN might contain a NULL and + ** the presence of a NULL on the RHS makes a difference in the + ** outcome. + */ + int j1; + + /* First check to see if the LHS is contained in the RHS. If so, + ** then the answer is TRUE the presence of NULLs in the RHS does + ** not matter. If the LHS is not contained in the RHS, then the + ** answer is NULL if the RHS contains NULLs and the answer is + ** FALSE if the RHS is NULL-free. + */ + j1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_IsNull, rRhsHasNull, destIfNull); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse); + sqlite3VdbeJumpHere(v, j1); + } } } sqlite3ReleaseTempReg(pParse, r1); - sqlite3ExprCachePop(pParse, 1); + sqlite3ExprCachePop(pParse); VdbeComment((v, "end IN expr")); } #endif /* SQLITE_OMIT_SUBQUERY */ @@ -79168,7 +80391,7 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){ i64 value; const char *z = pExpr->u.zToken; assert( z!=0 ); - c = sqlite3Atoi64(z, &value, sqlite3Strlen30(z), SQLITE_UTF8); + c = sqlite3DecOrHexToI64(z, &value); if( c==0 || (c==2 && negFlag) ){ char *zV; if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; } @@ -79178,7 +80401,14 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){ #ifdef SQLITE_OMIT_FLOATING_POINT sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z); #else - codeReal(v, z, negFlag, iMem); +#ifndef SQLITE_OMIT_HEX_INTEGER + if( sqlite3_strnicmp(z,"0x",2)==0 ){ + sqlite3ErrorMsg(pParse, "hex literal too big: %s", z); + }else +#endif + { + codeReal(v, z, negFlag, iMem); + } #endif } } @@ -79294,15 +80524,14 @@ SQLITE_PRIVATE void sqlite3ExprCachePush(Parse *pParse){ /* ** Remove from the column cache any entries that were added since the -** the previous N Push operations. In other words, restore the cache -** to the state it was in N Pushes ago. +** the previous sqlite3ExprCachePush operation. In other words, restore +** the cache to the state it was in prior the most recent Push. */ -SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse, int N){ +SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){ int i; struct yColCache *p; - assert( N>0 ); - assert( pParse->iCacheLevel>=N ); - pParse->iCacheLevel -= N; + assert( pParse->iCacheLevel>=1 ); + pParse->iCacheLevel--; #ifdef SQLITE_DEBUG if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ printf("POP to %d\n", pParse->iCacheLevel); @@ -79431,7 +80660,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int n int i; struct yColCache *p; assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo ); - sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg-1); + sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg); for(i=0, p=pParse->aColCache; iiReg; if( x>=iFrom && xu.zToken; nId = sqlite3Strlen30(zId); pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0); - if( pDef==0 ){ + if( pDef==0 || pDef->xFunc==0 ){ sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId); break; } @@ -79780,7 +81009,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) sqlite3ExprCacheRemove(pParse, target, 1); sqlite3ExprCachePush(pParse); sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target); - sqlite3ExprCachePop(pParse, 1); + sqlite3ExprCachePop(pParse); } sqlite3VdbeResolveLabel(v, endCoalesce); break; @@ -79832,9 +81061,9 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) } sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */ - sqlite3ExprCodeExprList(pParse, pFarg, r1, + sqlite3ExprCodeExprList(pParse, pFarg, r1, SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR); - sqlite3ExprCachePop(pParse, 1); /* Ticket 2ea2425d34be */ + sqlite3ExprCachePop(pParse); /* Ticket 2ea2425d34be */ }else{ r1 = 0; } @@ -80054,13 +81283,13 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) testcase( aListelem[i+1].pExpr->op==TK_COLUMN ); sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target); sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel); - sqlite3ExprCachePop(pParse, 1); + sqlite3ExprCachePop(pParse); sqlite3VdbeResolveLabel(v, nextCase); } if( (nExpr&1)!=0 ){ sqlite3ExprCachePush(pParse); sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target); - sqlite3ExprCachePop(pParse, 1); + sqlite3ExprCachePop(pParse); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, target); } @@ -80639,7 +81868,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int sqlite3ExprCachePush(pParse); sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); sqlite3VdbeResolveLabel(v, d2); - sqlite3ExprCachePop(pParse, 1); + sqlite3ExprCachePop(pParse); break; } case TK_OR: { @@ -80647,7 +81876,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); sqlite3ExprCachePush(pParse); sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); - sqlite3ExprCachePop(pParse, 1); + sqlite3ExprCachePop(pParse); break; } case TK_NOT: { @@ -80793,7 +82022,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); sqlite3ExprCachePush(pParse); sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); - sqlite3ExprCachePop(pParse, 1); + sqlite3ExprCachePop(pParse); break; } case TK_OR: { @@ -80803,7 +82032,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int sqlite3ExprCachePush(pParse); sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); sqlite3VdbeResolveLabel(v, d2); - sqlite3ExprCachePop(pParse, 1); + sqlite3ExprCachePop(pParse); break; } case TK_NOT: { @@ -81467,6 +82696,7 @@ static void renameParentFunc( int token; /* Type of token */ UNUSED_PARAMETER(NotUsed); + if( zInput==0 || zOld==0 ) return; for(z=zInput; *z; z=z+n){ n = sqlite3GetToken(z, &token); if( token==TK_REFERENCES ){ @@ -82426,6 +83656,7 @@ static void openStatTable( assert( i1 ); /* >1 because it includes the rowid column */ + assert( nCol>0 ); nColUp = sizeof(tRowcnt)<8 ? (nCol+1)&~1 : nCol; + nKeyCol = sqlite3_value_int(argv[1]); + assert( nKeyCol<=nCol ); + assert( nKeyCol>0 ); /* Allocate the space required for the Stat4Accum object */ n = sizeof(*p) @@ -82595,6 +83844,7 @@ static void statInit( p->db = db; p->nRow = 0; p->nCol = nCol; + p->nKeyCol = nKeyCol; p->current.anDLt = (tRowcnt*)&p[1]; p->current.anEq = &p->current.anDLt[nColUp]; @@ -82605,9 +83855,9 @@ static void statInit( p->iGet = -1; p->mxSample = mxSample; - p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[1])/(mxSample/3+1) + 1); + p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1); p->current.anLt = &p->current.anEq[nColUp]; - p->iPrn = nCol*0x689e962d ^ sqlite3_value_int(argv[1])*0xd0944565; + p->iPrn = nCol*0x689e962d ^ sqlite3_value_int(argv[2])*0xd0944565; /* Set up the Stat4Accum.a[] and aBest[] arrays */ p->a = (struct Stat4Sample*)&p->current.anLt[nColUp]; @@ -82630,7 +83880,7 @@ static void statInit( sqlite3_result_blob(context, p, sizeof(p), stat4Destructor); } static const FuncDef statInitFuncdef = { - 1+IsStat34, /* nArg */ + 2+IsStat34, /* nArg */ SQLITE_UTF8, /* funcFlags */ 0, /* pUserData */ 0, /* pNext */ @@ -82854,7 +84104,10 @@ static void samplePushPrevious(Stat4Accum *p, int iChng){ ** R Rowid for the current row. Might be a key record for ** WITHOUT ROWID tables. ** -** The SQL function always returns NULL. +** This SQL function always returns NULL. It's purpose it to accumulate +** statistical data and/or samples in the Stat4Accum object about the +** index being analyzed. The stat_get() SQL function will later be used to +** extract relevant information for constructing the sqlite_statN tables. ** ** The R parameter is only used for STAT3 and STAT4 */ @@ -82871,7 +84124,7 @@ static void statPush( UNUSED_PARAMETER( argc ); UNUSED_PARAMETER( context ); - assert( p->nCol>1 ); /* Includes rowid field */ + assert( p->nCol>0 ); assert( iChngnCol ); if( p->nRow==0 ){ @@ -82948,7 +84201,10 @@ static const FuncDef statPushFuncdef = { /* ** Implementation of the stat_get(P,J) SQL function. This routine is -** used to query the results. Content is returned for parameter J +** used to query statistical information that has been gathered into +** the Stat4Accum object by prior calls to stat_push(). The P parameter +** is a BLOB which is decoded into a pointer to the Stat4Accum objects. +** The content to returned is determined by the parameter J ** which is one of the STAT_GET_xxxx values defined above. ** ** If neither STAT3 nor STAT4 are enabled, then J is always @@ -82999,7 +84255,7 @@ static void statGet( char *z; int i; - char *zRet = sqlite3MallocZero(p->nCol * 25); + char *zRet = sqlite3MallocZero( (p->nKeyCol+1)*25 ); if( zRet==0 ){ sqlite3_result_error_nomem(context); return; @@ -83007,7 +84263,7 @@ static void statGet( sqlite3_snprintf(24, zRet, "%llu", (u64)p->nRow); z = zRet + sqlite3Strlen30(zRet); - for(i=0; i<(p->nCol-1); i++){ + for(i=0; inKeyCol; i++){ u64 nDistinct = p->current.anDLt[i] + 1; u64 iVal = (p->nRow + nDistinct - 1) / nDistinct; sqlite3_snprintf(24, z, " %llu", iVal); @@ -83167,27 +84423,27 @@ static void analyzeOneTable( sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - int nCol; /* Number of columns indexed by pIdx */ - int *aGotoChng; /* Array of jump instruction addresses */ + int nCol; /* Number of columns in pIdx. "N" */ int addrRewind; /* Address of "OP_Rewind iIdxCur" */ - int addrGotoChng0; /* Address of "Goto addr_chng_0" */ int addrNextRow; /* Address of "next_row:" */ const char *zIdxName; /* Name of the index */ + int nColTest; /* Number of columns to test for changes */ if( pOnlyIdx && pOnlyIdx!=pIdx ) continue; if( pIdx->pPartIdxWhere==0 ) needTableCnt = 0; - VdbeNoopComment((v, "Begin analysis of %s", pIdx->zName)); - nCol = pIdx->nKeyCol; - aGotoChng = sqlite3DbMallocRaw(db, sizeof(int)*(nCol+1)); - if( aGotoChng==0 ) continue; + if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIdx) ){ + nCol = pIdx->nKeyCol; + zIdxName = pTab->zName; + nColTest = nCol - 1; + }else{ + nCol = pIdx->nColumn; + zIdxName = pIdx->zName; + nColTest = pIdx->uniqNotNull ? pIdx->nKeyCol-1 : nCol-1; + } /* Populate the register containing the index name. */ - if( pIdx->autoIndex==2 && !HasRowid(pTab) ){ - zIdxName = pTab->zName; - }else{ - zIdxName = pIdx->zName; - } sqlite3VdbeAddOp4(v, OP_String8, 0, regIdxname, 0, zIdxName, 0); + VdbeComment((v, "Analysis for %s.%s", pTab->zName, zIdxName)); /* ** Pseudo-code for loop that calls stat_push(): @@ -83212,7 +84468,7 @@ static void analyzeOneTable( ** regPrev(1) = idx(1) ** ... ** - ** chng_addr_N: + ** endDistinctTest: ** regRowid = idx(rowid) ** stat_push(P, regChng, regRowid) ** Next csr @@ -83225,7 +84481,7 @@ static void analyzeOneTable( ** the regPrev array and a trailing rowid (the rowid slot is required ** when building a record to insert into the sample column of ** the sqlite_stat4 table. */ - pParse->nMem = MAX(pParse->nMem, regPrev+nCol); + pParse->nMem = MAX(pParse->nMem, regPrev+nColTest); /* Open a read-only cursor on the index being analyzed. */ assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) ); @@ -83235,18 +84491,22 @@ static void analyzeOneTable( /* Invoke the stat_init() function. The arguments are: ** - ** (1) the number of columns in the index including the rowid, - ** (2) the number of rows in the index, + ** (1) the number of columns in the index including the rowid + ** (or for a WITHOUT ROWID table, the number of PK columns), + ** (2) the number of columns in the key without the rowid/pk + ** (3) the number of rows in the index, ** - ** The second argument is only used for STAT3 and STAT4 + ** + ** The third argument is only used for STAT3 and STAT4 */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+2); + sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+3); #endif - sqlite3VdbeAddOp2(v, OP_Integer, nCol+1, regStat4+1); + sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1); + sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2); sqlite3VdbeAddOp3(v, OP_Function, 0, regStat4+1, regStat4); sqlite3VdbeChangeP4(v, -1, (char*)&statInitFuncdef, P4_FUNCDEF); - sqlite3VdbeChangeP5(v, 1+IsStat34); + sqlite3VdbeChangeP5(v, 2+IsStat34); /* Implementation of the following: ** @@ -83259,44 +84519,62 @@ static void analyzeOneTable( addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng); - addrGotoChng0 = sqlite3VdbeAddOp0(v, OP_Goto); - - /* - ** next_row: - ** regChng = 0 - ** if( idx(0) != regPrev(0) ) goto chng_addr_0 - ** regChng = 1 - ** if( idx(1) != regPrev(1) ) goto chng_addr_1 - ** ... - ** regChng = N - ** goto chng_addr_N - */ addrNextRow = sqlite3VdbeCurrentAddr(v); - for(i=0; iazColl[i]); - sqlite3VdbeAddOp2(v, OP_Integer, i, regChng); - sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regTemp); - aGotoChng[i] = - sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, regPrev+i, pColl, P4_COLLSEQ); - sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); - VdbeCoverage(v); - } - sqlite3VdbeAddOp2(v, OP_Integer, nCol, regChng); - aGotoChng[nCol] = sqlite3VdbeAddOp0(v, OP_Goto); - /* - ** chng_addr_0: - ** regPrev(0) = idx(0) - ** chng_addr_1: - ** regPrev(1) = idx(1) - ** ... - */ - sqlite3VdbeJumpHere(v, addrGotoChng0); - for(i=0; i0 ){ + int endDistinctTest = sqlite3VdbeMakeLabel(v); + int *aGotoChng; /* Array of jump instruction addresses */ + aGotoChng = sqlite3DbMallocRaw(db, sizeof(int)*nColTest); + if( aGotoChng==0 ) continue; + /* + ** next_row: + ** regChng = 0 + ** if( idx(0) != regPrev(0) ) goto chng_addr_0 + ** regChng = 1 + ** if( idx(1) != regPrev(1) ) goto chng_addr_1 + ** ... + ** regChng = N + ** goto endDistinctTest + */ + sqlite3VdbeAddOp0(v, OP_Goto); + addrNextRow = sqlite3VdbeCurrentAddr(v); + if( nColTest==1 && pIdx->nKeyCol==1 && IsUniqueIndex(pIdx) ){ + /* For a single-column UNIQUE index, once we have found a non-NULL + ** row, we know that all the rest will be distinct, so skip + ** subsequent distinctness tests. */ + sqlite3VdbeAddOp2(v, OP_NotNull, regPrev, endDistinctTest); + VdbeCoverage(v); + } + for(i=0; iazColl[i]); + sqlite3VdbeAddOp2(v, OP_Integer, i, regChng); + sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regTemp); + aGotoChng[i] = + sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, regPrev+i, pColl, P4_COLLSEQ); + sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); + VdbeCoverage(v); + } + sqlite3VdbeAddOp2(v, OP_Integer, nColTest, regChng); + sqlite3VdbeAddOp2(v, OP_Goto, 0, endDistinctTest); + + + /* + ** chng_addr_0: + ** regPrev(0) = idx(0) + ** chng_addr_1: + ** regPrev(1) = idx(1) + ** ... + */ + sqlite3VdbeJumpHere(v, addrNextRow-1); + for(i=0; inMem = MAX(pParse->nMem, regCol+nCol+1); + pParse->nMem = MAX(pParse->nMem, regCol+nCol); addrNext = sqlite3VdbeCurrentAddr(v); callStatGet(v, regStat4, STAT_GET_ROWID, regSampleRowid); @@ -83370,7 +84647,7 @@ static void analyzeOneTable( i16 iCol = pIdx->aiColumn[i]; sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, iCol, regCol+i); } - sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol+1, regSample); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol, regSample); #endif sqlite3VdbeAddOp3(v, OP_MakeRecord, regTabname, 6, regTemp); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur+1, regNewRowid); @@ -83382,7 +84659,6 @@ static void analyzeOneTable( /* End of analysis */ sqlite3VdbeJumpHere(v, addrRewind); - sqlite3DbFree(db, aGotoChng); } @@ -83483,6 +84759,7 @@ SQLITE_PRIVATE void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){ Table *pTab; Index *pIdx; Token *pTableName; + Vdbe *v; /* Read the database schema. If an error occurs, leave an error message ** and code in pParse and return NULL. */ @@ -83530,6 +84807,8 @@ SQLITE_PRIVATE void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){ } } } + v = sqlite3GetVdbe(pParse); + if( v ) sqlite3VdbeAddOp0(v, OP_Expire); } /* @@ -83551,6 +84830,7 @@ static void decodeIntArray( char *zIntArray, /* String containing int array to decode */ int nOut, /* Number of slots in aOut[] */ tRowcnt *aOut, /* Store integers here */ + LogEst *aLog, /* Or, if aOut==0, here */ Index *pIndex /* Handle extra flags for this index, if not NULL */ ){ char *z = zIntArray; @@ -83569,7 +84849,17 @@ static void decodeIntArray( v = v*10 + c - '0'; z++; } - aOut[i] = v; +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + if( aOut ){ + aOut[i] = v; + }else +#else + assert( aOut==0 ); + UNUSED_PARAMETER(aOut); +#endif + { + aLog[i] = sqlite3LogEst(v); + } if( *z==' ' ) z++; } #ifndef SQLITE_ENABLE_STAT3_OR_STAT4 @@ -83577,14 +84867,19 @@ static void decodeIntArray( #else if( pIndex ) #endif - { - if( strcmp(z, "unordered")==0 ){ + while( z[0] ){ + if( sqlite3_strglob("unordered*", z)==0 ){ pIndex->bUnordered = 1; }else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){ - int v32 = 0; - sqlite3GetInt32(z+3, &v32); - pIndex->szIdxRow = sqlite3LogEst(v32); + pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3)); } +#ifdef SQLITE_ENABLE_COSTMULT + else if( sqlite3_strglob("costmult=[0-9]*",z)==0 ){ + pIndex->pTable->costMult = sqlite3LogEst(sqlite3Atoi(z+9)); + } +#endif + while( z[0]!=0 && z[0]!=' ' ) z++; + while( z[0]==' ' ) z++; } } @@ -83625,12 +84920,16 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){ z = argv[2]; if( pIndex ){ - decodeIntArray((char*)z, pIndex->nKeyCol+1, pIndex->aiRowEst, pIndex); - if( pIndex->pPartIdxWhere==0 ) pTable->nRowEst = pIndex->aiRowEst[0]; + pIndex->bUnordered = 0; + decodeIntArray((char*)z, pIndex->nKeyCol+1, 0, pIndex->aiRowLogEst, pIndex); + if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0]; }else{ Index fakeIdx; fakeIdx.szIdxRow = pTable->szTabRow; - decodeIntArray((char*)z, 1, &pTable->nRowEst, &fakeIdx); +#ifdef SQLITE_ENABLE_COSTMULT + fakeIdx.pTable = pTable; +#endif + decodeIntArray((char*)z, 1, 0, &pTable->nRowLogEst, &fakeIdx); pTable->szTabRow = fakeIdx.szIdxRow; } @@ -83671,7 +84970,16 @@ static void initAvgEq(Index *pIdx){ IndexSample *aSample = pIdx->aSample; IndexSample *pFinal = &aSample[pIdx->nSample-1]; int iCol; - for(iCol=0; iColnKeyCol; iCol++){ + int nCol = 1; + if( pIdx->nSampleCol>1 ){ + /* If this is stat4 data, then calculate aAvgEq[] values for all + ** sample columns except the last. The last is always set to 1, as + ** once the trailing PK fields are considered all index keys are + ** unique. */ + nCol = pIdx->nSampleCol-1; + pIdx->aAvgEq[nCol] = 1; + } + for(iCol=0; iColaAvgEq[iCol] = avgEq; - if( pIdx->nSampleCol==1 ) break; } } } @@ -83753,7 +85060,6 @@ static int loadStatTbl( while( sqlite3_step(pStmt)==SQLITE_ROW ){ int nIdxCol = 1; /* Number of columns in stat4 records */ - int nAvgCol = 1; /* Number of entries in Index.aAvgEq */ char *zIndex; /* Index name */ Index *pIdx; /* Pointer to the index object */ @@ -83771,13 +85077,17 @@ static int loadStatTbl( ** loaded from the stat4 table. In this case ignore stat3 data. */ if( pIdx==0 || pIdx->nSample ) continue; if( bStat3==0 ){ - nIdxCol = pIdx->nKeyCol+1; - nAvgCol = pIdx->nKeyCol; + assert( !HasRowid(pIdx->pTable) || pIdx->nColumn==pIdx->nKeyCol+1 ); + if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){ + nIdxCol = pIdx->nKeyCol; + }else{ + nIdxCol = pIdx->nColumn; + } } pIdx->nSampleCol = nIdxCol; nByte = sizeof(IndexSample) * nSample; nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample; - nByte += nAvgCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */ + nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */ pIdx->aSample = sqlite3DbMallocZero(db, nByte); if( pIdx->aSample==0 ){ @@ -83785,7 +85095,7 @@ static int loadStatTbl( return SQLITE_NOMEM; } pSpace = (tRowcnt*)&pIdx->aSample[nSample]; - pIdx->aAvgEq = pSpace; pSpace += nAvgCol; + pIdx->aAvgEq = pSpace; pSpace += nIdxCol; for(i=0; iaSample[i].anEq = pSpace; pSpace += nIdxCol; pIdx->aSample[i].anLt = pSpace; pSpace += nIdxCol; @@ -83822,9 +85132,9 @@ static int loadStatTbl( pPrevIdx = pIdx; } pSample = &pIdx->aSample[pIdx->nSample]; - decodeIntArray((char*)sqlite3_column_text(pStmt,1), nCol, pSample->anEq, 0); - decodeIntArray((char*)sqlite3_column_text(pStmt,2), nCol, pSample->anLt, 0); - decodeIntArray((char*)sqlite3_column_text(pStmt,3), nCol, pSample->anDLt,0); + decodeIntArray((char*)sqlite3_column_text(pStmt,1),nCol,pSample->anEq,0,0); + decodeIntArray((char*)sqlite3_column_text(pStmt,2),nCol,pSample->anLt,0,0); + decodeIntArray((char*)sqlite3_column_text(pStmt,3),nCol,pSample->anDLt,0,0); /* Take a copy of the sample. Add two 0x00 bytes the end of the buffer. ** This is in case the sample record is corrupted. In that case, the @@ -84894,6 +86204,19 @@ static void codeTableLocks(Parse *pParse){ #define codeTableLocks(x) #endif +/* +** Return TRUE if the given yDbMask object is empty - if it contains no +** 1 bits. This routine is used by the DbMaskAllZero() and DbMaskNotZero() +** macros when SQLITE_MAX_ATTACHED is greater than 30. +*/ +#if SQLITE_MAX_ATTACHED>30 +SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask m){ + int i; + for(i=0; imallocFailed==0 && (pParse->cookieMask || pParse->pConstExpr) ){ - yDbMask mask; + if( db->mallocFailed==0 + && (DbMaskNonZero(pParse->cookieMask) || pParse->pConstExpr) + ){ int iDb, i; assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init ); sqlite3VdbeJumpHere(v, 0); - for(iDb=0, mask=1; iDbnDb; mask<<=1, iDb++){ - if( (mask & pParse->cookieMask)==0 ) continue; + for(iDb=0; iDbnDb; iDb++){ + if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue; sqlite3VdbeUsesBtree(v, iDb); sqlite3VdbeAddOp4Int(v, OP_Transaction, /* Opcode */ iDb, /* P1 */ - (mask & pParse->writeMask)!=0, /* P2 */ + DbMaskTest(pParse->writeMask,iDb), /* P2 */ pParse->cookieValue[iDb], /* P3 */ db->aDb[iDb].pSchema->iGeneration /* P4 */ ); @@ -84997,7 +86321,7 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ pParse->nMem = 0; pParse->nSet = 0; pParse->nVar = 0; - pParse->cookieMask = 0; + DbMaskZero(pParse->cookieMask); } /* @@ -85538,7 +86862,7 @@ SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *pParse, const char *zName){ */ SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table *pTab){ Index *p; - for(p=pTab->pIndex; p && p->autoIndex!=2; p=p->pNext){} + for(p=pTab->pIndex; p && !IsPrimaryKeyIndex(p); p=p->pNext){} return p; } @@ -85686,7 +87010,7 @@ SQLITE_PRIVATE void sqlite3StartTable( pTable->iPKey = -1; pTable->pSchema = db->aDb[iDb].pSchema; pTable->nRef = 1; - pTable->nRowEst = 1048576; + pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); assert( pParse->pNewTable==0 ); pParse->pNewTable = pTable; @@ -86067,7 +87391,7 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey( p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0); if( p ){ - p->autoIndex = 2; + p->idxType = SQLITE_IDXTYPE_PRIMARYKEY; if( v ) sqlite3VdbeJumpHere(v, pParse->addrSkipPK); } pList = 0; @@ -86087,7 +87411,10 @@ SQLITE_PRIVATE void sqlite3AddCheckConstraint( ){ #ifndef SQLITE_OMIT_CHECK Table *pTab = pParse->pNewTable; - if( pTab && !IN_DECLARE_VTAB ){ + sqlite3 *db = pParse->db; + if( pTab && !IN_DECLARE_VTAB + && !sqlite3BtreeIsReadonly(db->aDb[db->init.iDb].pBt) + ){ pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr); if( pParse->constraintName.n ){ sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1); @@ -86439,7 +87766,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ assert( pParse->pNewTable==pTab ); pPk = sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0); if( pPk==0 ) return; - pPk->autoIndex = 2; + pPk->idxType = SQLITE_IDXTYPE_PRIMARYKEY; pTab->iPKey = -1; }else{ pPk = sqlite3PrimaryKeyIndex(pTab); @@ -86462,7 +87789,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int n; - if( pIdx->autoIndex==2 ) continue; + if( IsPrimaryKeyIndex(pIdx) ) continue; for(i=n=0; iaiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ) n++; } @@ -86894,7 +88221,7 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ pSelTab->aCol = 0; sqlite3DeleteTable(db, pSelTab); assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) ); - pTable->pSchema->flags |= DB_UnresetViews; + pTable->pSchema->schemaFlags |= DB_UnresetViews; }else{ pTable->nCol = 0; nErr++; @@ -87461,7 +88788,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0); sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord); - sqlite3VdbeResolveLabel(v, iPartIdxLabel); + sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel); sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr1); if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb); @@ -87471,12 +88798,12 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v); assert( pKey!=0 || db->mallocFailed || pParse->nErr ); - if( pIndex->onError!=OE_None && pKey!=0 ){ + if( IsUniqueIndex(pIndex) && pKey!=0 ){ int j2 = sqlite3VdbeCurrentAddr(v) + 3; sqlite3VdbeAddOp2(v, OP_Goto, 0, j2); addr2 = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord, - pKey->nField - pIndex->nKeyCol); VdbeCoverage(v); + pIndex->nKeyCol); VdbeCoverage(v); sqlite3UniqueConstraint(pParse, OE_Abort, pIndex); }else{ addr2 = sqlite3VdbeCurrentAddr(v); @@ -87511,15 +88838,15 @@ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject( nByte = ROUND8(sizeof(Index)) + /* Index structure */ ROUND8(sizeof(char*)*nCol) + /* Index.azColl */ - ROUND8(sizeof(tRowcnt)*(nCol+1) + /* Index.aiRowEst */ + ROUND8(sizeof(LogEst)*(nCol+1) + /* Index.aiRowLogEst */ sizeof(i16)*nCol + /* Index.aiColumn */ sizeof(u8)*nCol); /* Index.aSortOrder */ p = sqlite3DbMallocZero(db, nByte + nExtra); if( p ){ char *pExtra = ((char*)p)+ROUND8(sizeof(Index)); - p->azColl = (char**)pExtra; pExtra += ROUND8(sizeof(char*)*nCol); - p->aiRowEst = (tRowcnt*)pExtra; pExtra += sizeof(tRowcnt)*(nCol+1); - p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol; + p->azColl = (char**)pExtra; pExtra += ROUND8(sizeof(char*)*nCol); + p->aiRowLogEst = (LogEst*)pExtra; pExtra += sizeof(LogEst)*(nCol+1); + p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol; p->aSortOrder = (u8*)pExtra; p->nColumn = nCol; p->nKeyCol = nCol - 1; @@ -87542,7 +88869,7 @@ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject( ** ** If the index is created successfully, return a pointer to the new Index ** structure. This is used by sqlite3AddPrimaryKey() to mark the index -** as the tables primary key (Index.autoIndex==2). +** as the tables primary key (Index.idxType==SQLITE_IDXTYPE_PRIMARYKEY) */ SQLITE_PRIVATE Index *sqlite3CreateIndex( Parse *pParse, /* All information about this parse */ @@ -87749,7 +89076,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex( if( db->mallocFailed ){ goto exit_create_index; } - assert( EIGHT_BYTE_ALIGNMENT(pIndex->aiRowEst) ); + assert( EIGHT_BYTE_ALIGNMENT(pIndex->aiRowLogEst) ); assert( EIGHT_BYTE_ALIGNMENT(pIndex->azColl) ); pIndex->zName = zExtra; zExtra += nName + 1; @@ -87757,7 +89084,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex( pIndex->pTable = pTab; pIndex->onError = (u8)onError; pIndex->uniqNotNull = onError!=OE_None; - pIndex->autoIndex = (u8)(pName==0); + pIndex->idxType = pName ? SQLITE_IDXTYPE_APPDEF : SQLITE_IDXTYPE_UNIQUE; pIndex->pSchema = db->aDb[iDb].pSchema; pIndex->nKeyCol = pList->nExpr; if( pPIWhere ){ @@ -87868,9 +89195,9 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex( Index *pIdx; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int k; - assert( pIdx->onError!=OE_None ); - assert( pIdx->autoIndex ); - assert( pIndex->onError!=OE_None ); + assert( IsUniqueIndex(pIdx) ); + assert( pIdx->idxType!=SQLITE_IDXTYPE_APPDEF ); + assert( IsUniqueIndex(pIndex) ); if( pIdx->nKeyCol!=pIndex->nKeyCol ) continue; for(k=0; knKeyCol; k++){ @@ -88030,7 +89357,7 @@ exit_create_index: ** Since we do not know, guess 1 million. aiRowEst[1] is an estimate of the ** number of rows in the table that match any particular value of the ** first column of the index. aiRowEst[2] is an estimate of the number -** of rows that match any particular combiniation of the first 2 columns +** of rows that match any particular combination of the first 2 columns ** of the index. And so forth. It must always be the case that * ** aiRowEst[N]<=aiRowEst[N-1] @@ -88041,20 +89368,27 @@ exit_create_index: ** are based on typical values found in actual indices. */ SQLITE_PRIVATE void sqlite3DefaultRowEst(Index *pIdx){ - tRowcnt *a = pIdx->aiRowEst; + /* 10, 9, 8, 7, 6 */ + LogEst aVal[] = { 33, 32, 30, 28, 26 }; + LogEst *a = pIdx->aiRowLogEst; + int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol); int i; - tRowcnt n; - assert( a!=0 ); - a[0] = pIdx->pTable->nRowEst; - if( a[0]<10 ) a[0] = 10; - n = 10; - for(i=1; i<=pIdx->nKeyCol; i++){ - a[i] = n; - if( n>5 ) n--; - } - if( pIdx->onError!=OE_None ){ - a[pIdx->nKeyCol] = 1; + + /* Set the first entry (number of rows in the index) to the estimated + ** number of rows in the table. Or 10, if the estimated number of rows + ** in the table is less than that. */ + a[0] = pIdx->pTable->nRowLogEst; + if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) ); + + /* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is + ** 6 and each subsequent value (if any) is 5. */ + memcpy(&a[1], aVal, nCopy*sizeof(LogEst)); + for(i=nCopy+1; i<=pIdx->nKeyCol; i++){ + a[i] = 23; assert( 23==sqlite3LogEst(5) ); } + + assert( 0==sqlite3LogEst(1) ); + if( IsUniqueIndex(pIdx) ) a[pIdx->nKeyCol] = 0; } /* @@ -88085,7 +89419,7 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists pParse->checkSchema = 1; goto exit_drop_index; } - if( pIndex->autoIndex ){ + if( pIndex->idxType!=SQLITE_IDXTYPE_APPDEF ){ sqlite3ErrorMsg(pParse, "index associated with UNIQUE " "or PRIMARY KEY constraint cannot be dropped", 0); goto exit_drop_index; @@ -88614,15 +89948,13 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){ SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){ Parse *pToplevel = sqlite3ParseToplevel(pParse); sqlite3 *db = pToplevel->db; - yDbMask mask; assert( iDb>=0 && iDbnDb ); assert( db->aDb[iDb].pBt!=0 || iDb==1 ); assert( iDbcookieMask & mask)==0 ){ - pToplevel->cookieMask |= mask; + if( DbMaskTest(pToplevel->cookieMask, iDb)==0 ){ + DbMaskSet(pToplevel->cookieMask, iDb); pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie; if( !OMIT_TEMPDB && iDb==1 ){ sqlite3OpenTempDatabase(pToplevel); @@ -88661,7 +89993,7 @@ SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb) SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){ Parse *pToplevel = sqlite3ParseToplevel(pParse); sqlite3CodeVerifySchema(pParse, iDb); - pToplevel->writeMask |= ((yDbMask)1)<writeMask, iDb); pToplevel->isMultiWrite |= setStatement; } @@ -88744,7 +90076,8 @@ SQLITE_PRIVATE void sqlite3UniqueConstraint( } zErr = sqlite3StrAccumFinish(&errMsg); sqlite3HaltConstraint(pParse, - (pIdx->autoIndex==2)?SQLITE_CONSTRAINT_PRIMARYKEY:SQLITE_CONSTRAINT_UNIQUE, + IsPrimaryKeyIndex(pIdx) ? SQLITE_CONSTRAINT_PRIMARYKEY + : SQLITE_CONSTRAINT_UNIQUE, onError, zErr, P4_DYNAMIC, P5_ConstraintUnique); } @@ -89467,9 +90800,9 @@ SQLITE_PRIVATE void sqlite3SchemaClear(void *p){ sqlite3HashClear(&temp1); sqlite3HashClear(&pSchema->fkeyHash); pSchema->pSeqTab = 0; - if( pSchema->flags & DB_SchemaLoaded ){ + if( pSchema->schemaFlags & DB_SchemaLoaded ){ pSchema->iGeneration++; - pSchema->flags &= ~DB_SchemaLoaded; + pSchema->schemaFlags &= ~DB_SchemaLoaded; } } @@ -90238,7 +91571,7 @@ SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete( &iPartIdxLabel, pPrior, r1); sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1, pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn); - sqlite3VdbeResolveLabel(v, iPartIdxLabel); + sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel); pPrior = pIdx; } } @@ -90257,10 +91590,11 @@ SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete( ** ** If *piPartIdxLabel is not NULL, fill it in with a label and jump ** to that label if pIdx is a partial index that should be skipped. +** The label should be resolved using sqlite3ResolvePartIdxLabel(). ** A partial index should be skipped if its WHERE clause evaluates ** to false or null. If pIdx is not a partial index, *piPartIdxLabel ** will be set to zero which is an empty label that is ignored by -** sqlite3VdbeResolveLabel(). +** sqlite3ResolvePartIdxLabel(). ** ** The pPrior and regPrior parameters are used to implement a cache to ** avoid unnecessary register loads. If pPrior is not NULL, then it is @@ -90293,6 +91627,7 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey( if( pIdx->pPartIdxWhere ){ *piPartIdxLabel = sqlite3VdbeMakeLabel(v); pParse->iPartIdxTab = iDataCur; + sqlite3ExprCachePush(pParse); sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, SQLITE_JUMPIFNULL); }else{ @@ -90321,6 +91656,18 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey( return regBase; } +/* +** If a prior call to sqlite3GenerateIndexKey() generated a jump-over label +** because it was a partial index, then this routine should be called to +** resolve that label. +*/ +SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){ + if( iLabel ){ + sqlite3VdbeResolveLabel(pParse->pVdbe, iLabel); + sqlite3ExprCachePop(pParse); + } +} + /************** End of delete.c **********************************************/ /************** Begin file func.c ********************************************/ /* @@ -90334,12 +91681,9 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey( ** May you share freely, never taking more than you give. ** ************************************************************************* -** This file contains the C functions that implement various SQL -** functions of SQLite. -** -** There is only one exported symbol in this file - the function -** sqliteRegisterBuildinFunctions() found at the bottom of the file. -** All other code has file scope. +** This file contains the C-language implementions for many of the SQL +** functions of SQLite. (Some function, and in particular the date and +** time functions, are implemented separately.) */ /* #include */ /* #include */ @@ -91864,7 +93208,7 @@ static void groupConcatStep( } zVal = (char*)sqlite3_value_text(argv[0]); nVal = sqlite3_value_bytes(argv[0]); - if( nVal ) sqlite3StrAccumAppend(pAccum, zVal, nVal); + if( zVal ) sqlite3StrAccumAppend(pAccum, zVal, nVal); } } static void groupConcatFinalize(sqlite3_context *context){ @@ -92014,6 +93358,7 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){ FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE), FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), + FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), VFUNCTION(random, 0, 0, 0, randomFunc ), VFUNCTION(randomblob, 1, 0, 0, randomBlob ), FUNCTION(nullif, 2, 0, 1, nullifFunc ), @@ -92300,7 +93645,7 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex( } for(pIdx=pParent->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->nKeyCol==nCol && pIdx->onError!=OE_None ){ + if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) ){ /* pIdx is a UNIQUE index (or a PRIMARY KEY) and has the right number ** of columns. If each indexed column corresponds to a foreign key ** column of pFKey, then this index is a winner. */ @@ -92308,8 +93653,8 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex( if( zKey==0 ){ /* If zKey is NULL, then this foreign key is implicitly mapped to ** the PRIMARY KEY of table pParent. The PRIMARY KEY index may be - ** identified by the test (Index.autoIndex==2). */ - if( pIdx->autoIndex==2 ){ + ** identified by the test. */ + if( IsPrimaryKeyIndex(pIdx) ){ if( aiCol ){ int i; for(i=0; iaCol[i].iFrom; @@ -94054,6 +95399,7 @@ SQLITE_PRIVATE void sqlite3Insert( if( j>=pTab->nCol ){ if( sqlite3IsRowid(pColumn->a[i].zName) && !withoutRowid ){ ipkColumn = i; + bIdListInOrder = 0; }else{ sqlite3ErrorMsg(pParse, "table %S has no column named %s", pTabList, 0, pColumn->a[i].zName); @@ -94902,7 +96248,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( ** KEY values of this row before the update. */ int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol; int op = OP_Ne; - int regCmp = (pIdx->autoIndex==2 ? regIdx : regR); + int regCmp = (IsPrimaryKeyIndex(pIdx) ? regIdx : regR); for(i=0; inKeyCol; i++){ char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]); @@ -95003,7 +96349,7 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i]); pik_flags = 0; if( useSeekResult ) pik_flags = OPFLAG_USESEEKRESULT; - if( pIdx->autoIndex==2 && !HasRowid(pTab) ){ + if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){ assert( pParse->nested==0 ); pik_flags |= OPFLAG_NCHANGE; } @@ -95089,7 +96435,7 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices( for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ int iIdxCur = iBase++; assert( pIdx->pSchema==pTab->pSchema ); - if( pIdx->autoIndex==2 && !HasRowid(pTab) && piDataCur ){ + if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) && piDataCur ){ *piDataCur = iIdxCur; } if( aToOpen==0 || aToOpen[i+1] ){ @@ -95305,18 +96651,27 @@ static int xferOptimization( return 0; /* Both tables must have the same INTEGER PRIMARY KEY */ } for(i=0; inCol; i++){ - if( pDest->aCol[i].affinity!=pSrc->aCol[i].affinity ){ + Column *pDestCol = &pDest->aCol[i]; + Column *pSrcCol = &pSrc->aCol[i]; + if( pDestCol->affinity!=pSrcCol->affinity ){ return 0; /* Affinity must be the same on all columns */ } - if( !xferCompatibleCollation(pDest->aCol[i].zColl, pSrc->aCol[i].zColl) ){ + if( !xferCompatibleCollation(pDestCol->zColl, pSrcCol->zColl) ){ return 0; /* Collating sequence must be the same on all columns */ } - if( pDest->aCol[i].notNull && !pSrc->aCol[i].notNull ){ + if( pDestCol->notNull && !pSrcCol->notNull ){ return 0; /* tab2 must be NOT NULL if tab1 is */ } + /* Default values for second and subsequent columns need to match. */ + if( i>0 + && ((pDestCol->zDflt==0)!=(pSrcCol->zDflt==0) + || (pDestCol->zDflt && strcmp(pDestCol->zDflt, pSrcCol->zDflt)!=0)) + ){ + return 0; /* Default values must be the same for all columns */ + } } for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){ - if( pDestIdx->onError!=OE_None ){ + if( IsUniqueIndex(pDestIdx) ){ destHasUniqueIdx = 1; } for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){ @@ -95546,6 +96901,9 @@ SQLITE_API int sqlite3_exec( } } if( xCallback(pArg, nCol, azVals, azCols) ){ + /* EVIDENCE-OF: R-38229-40159 If the callback function to + ** sqlite3_exec() returns non-zero, then sqlite3_exec() will + ** return SQLITE_ABORT. */ rc = SQLITE_ABORT; sqlite3VdbeFinalize((Vdbe *)pStmt); pStmt = 0; @@ -97323,7 +98681,7 @@ static const struct sPragmaNames { ** to support legacy SQL code. The safety level used to be boolean ** and older scripts may have used numbers 0 for OFF and 1 for ON. */ -static u8 getSafetyLevel(const char *z, int omitFull, int dflt){ +static u8 getSafetyLevel(const char *z, int omitFull, u8 dflt){ /* 123456789 123456789 */ static const char zText[] = "onoffalseyestruefull"; static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 16}; @@ -97345,7 +98703,7 @@ static u8 getSafetyLevel(const char *z, int omitFull, int dflt){ /* ** Interpret the given string as a boolean value. */ -SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z, int dflt){ +SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z, u8 dflt){ return getSafetyLevel(z,1,dflt)!=0; } @@ -97891,7 +99249,7 @@ SQLITE_PRIVATE void sqlite3Pragma( Pager *pPager = sqlite3BtreePager(pDb->pBt); i64 iLimit = -2; if( zRight ){ - sqlite3Atoi64(zRight, &iLimit, sqlite3Strlen30(zRight), SQLITE_UTF8); + sqlite3DecOrHexToI64(zRight, &iLimit); if( iLimit<-1 ) iLimit = -1; } iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit); @@ -98019,7 +99377,7 @@ SQLITE_PRIVATE void sqlite3Pragma( assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( zRight ){ int ii; - sqlite3Atoi64(zRight, &sz, sqlite3Strlen30(zRight), SQLITE_UTF8); + sqlite3DecOrHexToI64(zRight, &sz); if( sz<0 ) sz = sqlite3GlobalConfig.szMmap; if( pId2->n==0 ) db->szMmap = sz; for(ii=db->nDb-1; ii>=0; ii--){ @@ -98331,13 +99689,15 @@ SQLITE_PRIVATE void sqlite3Pragma( sqlite3VdbeAddOp2(v, OP_Null, 0, 2); sqlite3VdbeAddOp2(v, OP_Integer, (int)sqlite3LogEstToInt(pTab->szTabRow), 3); - sqlite3VdbeAddOp2(v, OP_Integer, (int)pTab->nRowEst, 4); + sqlite3VdbeAddOp2(v, OP_Integer, + (int)sqlite3LogEstToInt(pTab->nRowLogEst), 4); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0); sqlite3VdbeAddOp2(v, OP_Integer, (int)sqlite3LogEstToInt(pIdx->szIdxRow), 3); - sqlite3VdbeAddOp2(v, OP_Integer, (int)pIdx->aiRowEst[0], 4); + sqlite3VdbeAddOp2(v, OP_Integer, + (int)sqlite3LogEstToInt(pIdx->aiRowLogEst[0]), 4); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4); } } @@ -98385,7 +99745,7 @@ SQLITE_PRIVATE void sqlite3Pragma( for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){ sqlite3VdbeAddOp2(v, OP_Integer, i, 1); sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0); - sqlite3VdbeAddOp2(v, OP_Integer, pIdx->onError!=OE_None, 3); + sqlite3VdbeAddOp2(v, OP_Integer, IsUniqueIndex(pIdx), 3); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); } } @@ -98635,9 +99995,8 @@ SQLITE_PRIVATE void sqlite3Pragma( */ static const int iLn = VDBE_OFFSET_LINENO(2); static const VdbeOpList endCode[] = { - { OP_AddImm, 1, 0, 0}, /* 0 */ - { OP_IfNeg, 1, 0, 0}, /* 1 */ - { OP_String8, 0, 3, 0}, /* 2 */ + { OP_IfNeg, 1, 0, 0}, /* 0 */ + { OP_String8, 0, 3, 0}, /* 1 */ { OP_ResultRow, 3, 1, 0}, }; @@ -98718,7 +100077,7 @@ SQLITE_PRIVATE void sqlite3Pragma( sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName), P4_DYNAMIC); - sqlite3VdbeAddOp2(v, OP_Move, 2, 4); + sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2); sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1); sqlite3VdbeJumpHere(v, addr); @@ -98749,29 +100108,77 @@ SQLITE_PRIVATE void sqlite3Pragma( pParse->nMem = MAX(pParse->nMem, 8+j); sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v); loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1); + /* Verify that all NOT NULL columns really are NOT NULL */ + for(j=0; jnCol; j++){ + char *zErr; + int jmp2, jmp3; + if( j==pTab->iPKey ) continue; + if( pTab->aCol[j].notNull==0 ) continue; + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3); + sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); + jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */ + zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName, + pTab->aCol[j].zName); + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); + sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1); + jmp3 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v); + sqlite3VdbeAddOp0(v, OP_Halt); + sqlite3VdbeJumpHere(v, jmp2); + sqlite3VdbeJumpHere(v, jmp3); + } + /* Validate index entries for the current row */ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ - int jmp2, jmp3, jmp4; + int jmp2, jmp3, jmp4, jmp5; + int ckUniq = sqlite3VdbeMakeLabel(v); if( pPk==pIdx ) continue; r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3, pPrior, r1); pPrior = pIdx; sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1); /* increment entry count */ - jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, 0, r1, + /* Verify that an index entry exists for the current table row */ + jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1, pIdx->nColumn); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, "row ", P4_STATIC); sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3); - sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, " missing from index ", - P4_STATIC); + sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, + " missing from index ", P4_STATIC); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); - sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, pIdx->zName, P4_TRANSIENT); + jmp5 = sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, + pIdx->zName, P4_TRANSIENT); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1); jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v); sqlite3VdbeAddOp0(v, OP_Halt); - sqlite3VdbeJumpHere(v, jmp4); sqlite3VdbeJumpHere(v, jmp2); - sqlite3VdbeResolveLabel(v, jmp3); + /* For UNIQUE indexes, verify that only one entry exists with the + ** current key. The entry is unique if (1) any column is NULL + ** or (2) the next entry has a different key */ + if( IsUniqueIndex(pIdx) ){ + int uniqOk = sqlite3VdbeMakeLabel(v); + int jmp6; + int kk; + for(kk=0; kknKeyCol; kk++){ + int iCol = pIdx->aiColumn[kk]; + assert( iCol>=0 && iColnCol ); + if( pTab->aCol[iCol].notNull ) continue; + sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk); + VdbeCoverage(v); + } + jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Goto, 0, uniqOk); + sqlite3VdbeJumpHere(v, jmp6); + sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1, + pIdx->nKeyCol); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */ + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, + "non-unique entry in index ", P4_STATIC); + sqlite3VdbeAddOp2(v, OP_Goto, 0, jmp5); + sqlite3VdbeResolveLabel(v, uniqOk); + } + sqlite3VdbeJumpHere(v, jmp4); + sqlite3ResolvePartIdxLabel(pParse, jmp3); } sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v); sqlite3VdbeJumpHere(v, loopTop-1); @@ -98795,9 +100202,9 @@ SQLITE_PRIVATE void sqlite3Pragma( } } addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn); - sqlite3VdbeChangeP2(v, addr, -mxErr); - sqlite3VdbeJumpHere(v, addr+1); - sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC); + sqlite3VdbeChangeP3(v, addr, -mxErr); + sqlite3VdbeJumpHere(v, addr); + sqlite3VdbeChangeP4(v, addr+1, "ok", P4_STATIC); } break; #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ @@ -99060,7 +100467,7 @@ SQLITE_PRIVATE void sqlite3Pragma( */ case PragTyp_SOFT_HEAP_LIMIT: { sqlite3_int64 N; - if( zRight && sqlite3Atoi64(zRight, &N, 1000000, SQLITE_UTF8)==SQLITE_OK ){ + if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){ sqlite3_soft_heap_limit64(N); } returnSingleInt(pParse, "soft_heap_limit", sqlite3_soft_heap_limit64(-1)); @@ -100056,6 +101463,34 @@ SQLITE_API int sqlite3_prepare16_v2( ** to handle SELECT statements in SQLite. */ +/* +** An instance of the following object is used to record information about +** how to process the DISTINCT keyword, to simplify passing that information +** into the selectInnerLoop() routine. +*/ +typedef struct DistinctCtx DistinctCtx; +struct DistinctCtx { + u8 isTnct; /* True if the DISTINCT keyword is present */ + u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */ + int tabTnct; /* Ephemeral table used for DISTINCT processing */ + int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */ +}; + +/* +** An instance of the following object is used to record information about +** the ORDER BY (or GROUP BY) clause of query is being coded. +*/ +typedef struct SortCtx SortCtx; +struct SortCtx { + ExprList *pOrderBy; /* The ORDER BY (or GROUP BY clause) */ + int nOBSat; /* Number of ORDER BY terms satisfied by indices */ + int iECursor; /* Cursor number for the sorter */ + int regReturn; /* Register holding block-output return address */ + int labelBkOut; /* Start label for the block-output subroutine */ + int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */ + u8 sortFlags; /* Zero or more SORTFLAG_* bits */ +}; +#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */ /* ** Delete all the content of a Select structure but do not deallocate @@ -100129,7 +101564,6 @@ SQLITE_PRIVATE Select *sqlite3SelectNew( assert( pOffset==0 || pLimit!=0 ); pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; - pNew->addrOpenEphm[2] = -1; if( db->mallocFailed ) { clearSelect(db, pNew); if( pNew!=&standin ) sqlite3DbFree(db, pNew); @@ -100461,34 +101895,73 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ return 0; } +/* Forward reference */ +static KeyInfo *keyInfoFromExprList( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* Form the KeyInfo object from this ExprList */ + int iStart, /* Begin with this column of pList */ + int nExtra /* Add this many extra columns to the end */ +); + /* -** Insert code into "v" that will push the record on the top of the -** stack into the sorter. +** Insert code into "v" that will push the record in register regData +** into the sorter. */ static void pushOntoSorter( Parse *pParse, /* Parser context */ - ExprList *pOrderBy, /* The ORDER BY clause */ + SortCtx *pSort, /* Information about the ORDER BY clause */ Select *pSelect, /* The whole SELECT statement */ int regData /* Register holding data to be sorted */ ){ Vdbe *v = pParse->pVdbe; - int nExpr = pOrderBy->nExpr; - int regBase = sqlite3GetTempRange(pParse, nExpr+2); - int regRecord = sqlite3GetTempReg(pParse); + int nExpr = pSort->pOrderBy->nExpr; + int regRecord = ++pParse->nMem; + int regBase = pParse->nMem+1; + int nOBSat = pSort->nOBSat; int op; + + pParse->nMem += nExpr+2; /* nExpr+2 registers allocated at regBase */ sqlite3ExprCacheClear(pParse); - sqlite3ExprCodeExprList(pParse, pOrderBy, regBase, 0); - sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr); + sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, 0); + sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr); sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1); - sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nExpr + 2, regRecord); - if( pSelect->selFlags & SF_UseSorter ){ + sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nExpr+2-nOBSat,regRecord); + if( nOBSat>0 ){ + int regPrevKey; /* The first nOBSat columns of the previous row */ + int addrFirst; /* Address of the OP_IfNot opcode */ + int addrJmp; /* Address of the OP_Jump opcode */ + VdbeOp *pOp; /* Opcode that opens the sorter */ + int nKey; /* Number of sorting key columns, including OP_Sequence */ + KeyInfo *pKI; /* Original KeyInfo on the sorter table */ + + regPrevKey = pParse->nMem+1; + pParse->nMem += pSort->nOBSat; + nKey = nExpr - pSort->nOBSat + 1; + addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Compare, regPrevKey, regBase, pSort->nOBSat); + pOp = sqlite3VdbeGetOp(v, pSort->addrSortIndex); + if( pParse->db->mallocFailed ) return; + pOp->p2 = nKey + 1; + pKI = pOp->p4.pKeyInfo; + memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */ + sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO); + pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat, 1); + addrJmp = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v); + pSort->labelBkOut = sqlite3VdbeMakeLabel(v); + pSort->regReturn = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut); + sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor); + sqlite3VdbeJumpHere(v, addrFirst); + sqlite3VdbeAddOp3(v, OP_Move, regBase, regPrevKey, pSort->nOBSat); + sqlite3VdbeJumpHere(v, addrJmp); + } + if( pSort->sortFlags & SORTFLAG_UseSorter ){ op = OP_SorterInsert; }else{ op = OP_IdxInsert; } - sqlite3VdbeAddOp2(v, op, pOrderBy->iECursor, regRecord); - sqlite3ReleaseTempReg(pParse, regRecord); - sqlite3ReleaseTempRange(pParse, regBase, nExpr+2); + sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord); if( pSelect->iLimit ){ int addr1, addr2; int iLimit; @@ -100501,8 +101974,8 @@ static void pushOntoSorter( sqlite3VdbeAddOp2(v, OP_AddImm, iLimit, -1); addr2 = sqlite3VdbeAddOp0(v, OP_Goto); sqlite3VdbeJumpHere(v, addr1); - sqlite3VdbeAddOp1(v, OP_Last, pOrderBy->iECursor); - sqlite3VdbeAddOp1(v, OP_Delete, pOrderBy->iECursor); + sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor); + sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor); sqlite3VdbeJumpHere(v, addr2); } } @@ -100515,10 +101988,9 @@ static void codeOffset( int iOffset, /* Register holding the offset counter */ int iContinue /* Jump here to skip the current record */ ){ - if( iOffset>0 && iContinue!=0 ){ + if( iOffset>0 ){ int addr; - sqlite3VdbeAddOp2(v, OP_AddImm, iOffset, -1); - addr = sqlite3VdbeAddOp1(v, OP_IfNeg, iOffset); VdbeCoverage(v); + addr = sqlite3VdbeAddOp3(v, OP_IfNeg, iOffset, 0, -1); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Goto, 0, iContinue); VdbeComment((v, "skip OFFSET records")); sqlite3VdbeJumpHere(v, addr); @@ -100576,19 +102048,6 @@ static int checkForMultiColumnSelectError( } #endif -/* -** An instance of the following object is used to record information about -** how to process the DISTINCT keyword, to simplify passing that information -** into the selectInnerLoop() routine. -*/ -typedef struct DistinctCtx DistinctCtx; -struct DistinctCtx { - u8 isTnct; /* True if the DISTINCT keyword is present */ - u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */ - int tabTnct; /* Ephemeral table used for DISTINCT processing */ - int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */ -}; - /* ** This routine generates the code for the inside of the inner loop ** of a SELECT. @@ -100603,7 +102062,7 @@ static void selectInnerLoop( Select *p, /* The complete select statement being coded */ ExprList *pEList, /* List of values being extracted */ int srcTab, /* Pull data from this table */ - ExprList *pOrderBy, /* If not NULL, sort results using this key */ + SortCtx *pSort, /* If not NULL, info on how to process ORDER BY */ DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */ SelectDest *pDest, /* How to dispose of the results */ int iContinue, /* Jump here to continue with next row */ @@ -100620,7 +102079,9 @@ static void selectInnerLoop( assert( v ); assert( pEList!=0 ); hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP; - if( pOrderBy==0 && !hasDistinct ){ + if( pSort && pSort->pOrderBy==0 ) pSort = 0; + if( pSort==0 && !hasDistinct ){ + assert( iContinue!=0 ); codeOffset(v, p->iOffset, iContinue); } @@ -100694,7 +102155,7 @@ static void selectInnerLoop( sqlite3VdbeChangeP4(v, -1, (const char *)pColl, P4_COLLSEQ); sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); } - assert( sqlite3VdbeCurrentAddr(v)==iJump ); + assert( sqlite3VdbeCurrentAddr(v)==iJump || pParse->db->mallocFailed ); sqlite3VdbeAddOp3(v, OP_Copy, regResult, regPrev, nResultCol-1); break; } @@ -100710,7 +102171,7 @@ static void selectInnerLoop( break; } } - if( pOrderBy==0 ){ + if( pSort==0 ){ codeOffset(v, p->iOffset, iContinue); } } @@ -100741,7 +102202,8 @@ static void selectInnerLoop( /* Store the result as data using a unique key. */ - case SRT_DistTable: + case SRT_Fifo: + case SRT_DistFifo: case SRT_Table: case SRT_EphemTab: { int r1 = sqlite3GetTempReg(pParse); @@ -100749,8 +102211,8 @@ static void selectInnerLoop( testcase( eDest==SRT_EphemTab ); sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1); #ifndef SQLITE_OMIT_CTE - if( eDest==SRT_DistTable ){ - /* If the destination is DistTable, then cursor (iParm+1) is open + if( eDest==SRT_DistFifo ){ + /* If the destination is DistFifo, then cursor (iParm+1) is open ** on an ephemeral index. If the current row is already present ** in the index, do not write it to the output. If not, add the ** current row to the index and proceed with writing it to the @@ -100758,11 +102220,11 @@ static void selectInnerLoop( int addr = sqlite3VdbeCurrentAddr(v) + 4; sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1); - assert( pOrderBy==0 ); + assert( pSort==0 ); } #endif - if( pOrderBy ){ - pushOntoSorter(pParse, pOrderBy, p, r1); + if( pSort ){ + pushOntoSorter(pParse, pSort, p, r1); }else{ int r2 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2); @@ -100783,12 +102245,12 @@ static void selectInnerLoop( assert( nResultCol==1 ); pDest->affSdst = sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst); - if( pOrderBy ){ + if( pSort ){ /* At first glance you would think we could optimize out the ** ORDER BY in this case since the order of entries in the set ** does not matter. But there might be a LIMIT clause, in which ** case the order does matter */ - pushOntoSorter(pParse, pOrderBy, p, regResult); + pushOntoSorter(pParse, pSort, p, regResult); }else{ int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1); @@ -100813,8 +102275,8 @@ static void selectInnerLoop( */ case SRT_Mem: { assert( nResultCol==1 ); - if( pOrderBy ){ - pushOntoSorter(pParse, pOrderBy, p, regResult); + if( pSort ){ + pushOntoSorter(pParse, pSort, p, regResult); }else{ sqlite3ExprCodeMove(pParse, regResult, iParm, 1); /* The LIMIT clause will jump out of the loop for us */ @@ -100827,10 +102289,10 @@ static void selectInnerLoop( case SRT_Output: { /* Return the results */ testcase( eDest==SRT_Coroutine ); testcase( eDest==SRT_Output ); - if( pOrderBy ){ + if( pSort ){ int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1); - pushOntoSorter(pParse, pOrderBy, p, r1); + pushOntoSorter(pParse, pSort, p, r1); sqlite3ReleaseTempReg(pParse, r1); }else if( eDest==SRT_Coroutine ){ sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); @@ -100907,7 +102369,7 @@ static void selectInnerLoop( ** there is a sorter, in which case the sorter has already limited ** the output for us. */ - if( pOrderBy==0 && p->iLimit ){ + if( pSort==0 && p->iLimit ){ sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v); } } @@ -100978,7 +102440,12 @@ SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo *p){ return p->nRef==1; } ** function is responsible for seeing that this structure is eventually ** freed. */ -static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList, int nExtra){ +static KeyInfo *keyInfoFromExprList( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* Form the KeyInfo object from this ExprList */ + int iStart, /* Begin with this column of pList */ + int nExtra /* Add this many extra columns to the end */ +){ int nExpr; KeyInfo *pInfo; struct ExprList_item *pItem; @@ -100986,15 +102453,15 @@ static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList, int nExtra){ int i; nExpr = pList->nExpr; - pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra, 1); + pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra-iStart, 1); if( pInfo ){ assert( sqlite3KeyInfoIsWriteable(pInfo) ); - for(i=0, pItem=pList->a; ia+iStart; ipExpr); if( !pColl ) pColl = db->pDfltColl; - pInfo->aColl[i] = pColl; - pInfo->aSortOrder[i] = pItem->sortOrder; + pInfo->aColl[i-iStart] = pColl; + pInfo->aSortOrder[i-iStart] = pItem->sortOrder; } } return pInfo; @@ -101096,24 +102563,31 @@ static void explainComposite( static void generateSortTail( Parse *pParse, /* Parsing context */ Select *p, /* The SELECT statement */ - Vdbe *v, /* Generate code into this VDBE */ + SortCtx *pSort, /* Information on the ORDER BY clause */ int nColumn, /* Number of columns of data */ SelectDest *pDest /* Write the sorted results here */ ){ + Vdbe *v = pParse->pVdbe; /* The prepared statement */ int addrBreak = sqlite3VdbeMakeLabel(v); /* Jump here to exit loop */ int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */ int addr; + int addrOnce = 0; int iTab; int pseudoTab = 0; - ExprList *pOrderBy = p->pOrderBy; - + ExprList *pOrderBy = pSort->pOrderBy; int eDest = pDest->eDest; int iParm = pDest->iSDParm; - int regRow; int regRowid; + int nKey; - iTab = pOrderBy->iECursor; + if( pSort->labelBkOut ){ + sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut); + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrBreak); + sqlite3VdbeResolveLabel(v, pSort->labelBkOut); + addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v); + } + iTab = pSort->iECursor; regRow = sqlite3GetTempReg(pParse); if( eDest==SRT_Output || eDest==SRT_Coroutine ){ pseudoTab = pParse->nTab++; @@ -101122,20 +102596,23 @@ static void generateSortTail( }else{ regRowid = sqlite3GetTempReg(pParse); } - if( p->selFlags & SF_UseSorter ){ + nKey = pOrderBy->nExpr - pSort->nOBSat; + if( pSort->sortFlags & SORTFLAG_UseSorter ){ int regSortOut = ++pParse->nMem; int ptab2 = pParse->nTab++; - sqlite3VdbeAddOp3(v, OP_OpenPseudo, ptab2, regSortOut, pOrderBy->nExpr+2); + sqlite3VdbeAddOp3(v, OP_OpenPseudo, ptab2, regSortOut, nKey+2); + if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak); VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); sqlite3VdbeAddOp2(v, OP_SorterData, iTab, regSortOut); - sqlite3VdbeAddOp3(v, OP_Column, ptab2, pOrderBy->nExpr+1, regRow); + sqlite3VdbeAddOp3(v, OP_Column, ptab2, nKey+1, regRow); sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE); }else{ + if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); - sqlite3VdbeAddOp3(v, OP_Column, iTab, pOrderBy->nExpr+1, regRow); + sqlite3VdbeAddOp3(v, OP_Column, iTab, nKey+1, regRow); } switch( eDest ){ case SRT_Table: @@ -101190,15 +102667,13 @@ static void generateSortTail( /* The bottom of the loop */ sqlite3VdbeResolveLabel(v, addrContinue); - if( p->selFlags & SF_UseSorter ){ + if( pSort->sortFlags & SORTFLAG_UseSorter ){ sqlite3VdbeAddOp2(v, OP_SorterNext, iTab, addr); VdbeCoverage(v); }else{ sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); VdbeCoverage(v); } + if( pSort->regReturn ) sqlite3VdbeAddOp1(v, OP_Return, pSort->regReturn); sqlite3VdbeResolveLabel(v, addrBreak); - if( eDest==SRT_Output || eDest==SRT_Coroutine ){ - sqlite3VdbeAddOp2(v, OP_Close, pseudoTab, 0); - } } /* @@ -101658,7 +103133,7 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){ assert( db->lookaside.bEnabled==0 ); pTab->nRef = 1; pTab->zName = 0; - pTab->nRowEst = 1048576; + pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol); selectAddColumnTypeAndCollation(pParse, pTab, pSelect); pTab->iPKey = -1; @@ -101876,7 +103351,7 @@ static void generateWithRecursiveQuery( int regCurrent; /* Register holding Current table */ int iQueue; /* The Queue table */ int iDistinct = 0; /* To ensure unique results if UNION */ - int eDest = SRT_Table; /* How to write to Queue */ + int eDest = SRT_Fifo; /* How to write to Queue */ SelectDest destQueue; /* SelectDest targetting the Queue table */ int i; /* Loop counter */ int rc; /* Result code */ @@ -101908,13 +103383,13 @@ static void generateWithRecursiveQuery( /* Allocate cursors numbers for Queue and Distinct. The cursor number for ** the Distinct table must be exactly one greater than Queue in order - ** for the SRT_DistTable and SRT_DistQueue destinations to work. */ + ** for the SRT_DistFifo and SRT_DistQueue destinations to work. */ iQueue = pParse->nTab++; if( p->op==TK_UNION ){ - eDest = pOrderBy ? SRT_DistQueue : SRT_DistTable; + eDest = pOrderBy ? SRT_DistQueue : SRT_DistFifo; iDistinct = pParse->nTab++; }else{ - eDest = pOrderBy ? SRT_Queue : SRT_Table; + eDest = pOrderBy ? SRT_Queue : SRT_Fifo; } sqlite3SelectDestInit(&destQueue, eDest, iQueue); @@ -101980,6 +103455,7 @@ static void generateWithRecursiveQuery( sqlite3VdbeResolveLabel(v, addrBreak); end_of_recursive_query: + sqlite3ExprListDelete(pParse->db, p->pOrderBy); p->pOrderBy = pOrderBy; p->pLimit = pLimit; p->pOffset = pOffset; @@ -103796,7 +105272,7 @@ static int withExpand( pTab->nRef = 1; pTab->zName = sqlite3DbStrDup(db, pCte->zName); pTab->iPKey = -1; - pTab->nRowEst = 1048576; + pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); pTab->tabFlags |= TF_Ephemeral; pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0); if( db->mallocFailed ) return SQLITE_NOMEM; @@ -103972,7 +105448,7 @@ static int selectExpander(Walker *pWalker, Select *p){ while( pSel->pPrior ){ pSel = pSel->pPrior; } selectColumnsFromExprList(pParse, pSel->pEList, &pTab->nCol, &pTab->aCol); pTab->iPKey = -1; - pTab->nRowEst = 1048576; + pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); pTab->tabFlags |= TF_Ephemeral; #endif }else{ @@ -104351,7 +105827,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){ "argument"); pFunc->iDistinct = -1; }else{ - KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0); + KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0, 0); sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0, (char*)pKeyInfo, P4_KEYINFO); } @@ -104467,10 +105943,11 @@ static void explainSimpleCount( Index *pIdx /* Index used to optimize scan, or NULL */ ){ if( pParse->explain==2 ){ + int bCover = (pIdx!=0 && (HasRowid(pTab) || !IsPrimaryKeyIndex(pIdx))); char *zEqp = sqlite3MPrintf(pParse->db, "SCAN TABLE %s%s%s", - pTab->zName, - pIdx ? " USING COVERING INDEX " : "", - pIdx ? pIdx->zName : "" + pTab->zName, + bCover ? " USING COVERING INDEX " : "", + bCover ? pIdx->zName : "" ); sqlite3VdbeAddOp4( pParse->pVdbe, OP_Explain, pParse->iSelectId, 0, 0, zEqp, P4_DYNAMIC @@ -104506,12 +105983,11 @@ SQLITE_PRIVATE int sqlite3Select( ExprList *pEList; /* List of columns to extract. */ SrcList *pTabList; /* List of tables to select from */ Expr *pWhere; /* The WHERE clause. May be NULL */ - ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */ ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */ Expr *pHaving; /* The HAVING clause. May be NULL */ int rc = 1; /* Value to return from this function */ - int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */ DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */ + SortCtx sSort; /* Info on how to code the ORDER BY clause */ AggInfo sAggInfo; /* Information used by aggregate queries */ int iEnd; /* Address of the end of the query */ sqlite3 *db; /* The database connection */ @@ -104528,9 +106004,15 @@ SQLITE_PRIVATE int sqlite3Select( if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; memset(&sAggInfo, 0, sizeof(sAggInfo)); + assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo ); + assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo ); + assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue ); + assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue ); if( IgnorableOrderby(pDest) ){ assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union || - pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard); + pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard || + pDest->eDest==SRT_Queue || pDest->eDest==SRT_DistFifo || + pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_Fifo); /* If ORDER BY makes no difference in the output then neither does ** DISTINCT so it can be removed too. */ sqlite3ExprListDelete(db, p->pOrderBy); @@ -104538,7 +106020,8 @@ SQLITE_PRIVATE int sqlite3Select( p->selFlags &= ~SF_Distinct; } sqlite3SelectPrep(pParse, p, 0); - pOrderBy = p->pOrderBy; + memset(&sSort, 0, sizeof(sSort)); + sSort.pOrderBy = p->pOrderBy; pTabList = p->pSrc; pEList = p->pEList; if( pParse->nErr || db->mallocFailed ){ @@ -104616,7 +106099,7 @@ SQLITE_PRIVATE int sqlite3Select( sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); sqlite3Select(pParse, pSub, &dest); - pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow; + pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow); pItem->viaCoroutine = 1; pItem->regResult = dest.iSdst; sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn); @@ -104647,7 +106130,7 @@ SQLITE_PRIVATE int sqlite3Select( sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); sqlite3Select(pParse, pSub, &dest); - pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow; + pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow); if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr); retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn); VdbeComment((v, "end %s", pItem->pTab->zName)); @@ -104660,7 +106143,7 @@ SQLITE_PRIVATE int sqlite3Select( pParse->nHeight -= sqlite3SelectExprHeight(p); pTabList = p->pSrc; if( !IgnorableOrderby(pDest) ){ - pOrderBy = p->pOrderBy; + sSort.pOrderBy = p->pOrderBy; } } pEList = p->pEList; @@ -104680,18 +106163,6 @@ SQLITE_PRIVATE int sqlite3Select( } #endif - /* If there is both a GROUP BY and an ORDER BY clause and they are - ** identical, then disable the ORDER BY clause since the GROUP BY - ** will cause elements to come out in the correct order. This is - ** an optimization - the correct answer should result regardless. - ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER - ** to disable this optimization for testing purposes. - */ - if( sqlite3ExprListCompare(p->pGroupBy, pOrderBy, -1)==0 - && OptimizationEnabled(db, SQLITE_GroupByOrder) ){ - pOrderBy = 0; - } - /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and ** if the select-list is the same as the ORDER BY list, then this query ** can be rewritten as a GROUP BY. In other words, this: @@ -104708,12 +106179,12 @@ SQLITE_PRIVATE int sqlite3Select( ** BY and DISTINCT, and an index or separate temp-table for the other. */ if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct - && sqlite3ExprListCompare(pOrderBy, p->pEList, -1)==0 + && sqlite3ExprListCompare(sSort.pOrderBy, p->pEList, -1)==0 ){ p->selFlags &= ~SF_Distinct; p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0); pGroupBy = p->pGroupBy; - pOrderBy = 0; + sSort.pOrderBy = 0; /* Notice that even thought SF_Distinct has been cleared from p->selFlags, ** the sDistinct.isTnct is still set. Hence, isTnct represents the ** original setting of the SF_Distinct flag, not the current setting */ @@ -104727,16 +106198,16 @@ SQLITE_PRIVATE int sqlite3Select( ** we figure out that the sorting index is not needed. The addrSortIndex ** variable is used to facilitate that change. */ - if( pOrderBy ){ + if( sSort.pOrderBy ){ KeyInfo *pKeyInfo; - pKeyInfo = keyInfoFromExprList(pParse, pOrderBy, 0); - pOrderBy->iECursor = pParse->nTab++; - p->addrOpenEphm[2] = addrSortIndex = + pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, 0); + sSort.iECursor = pParse->nTab++; + sSort.addrSortIndex = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, - pOrderBy->iECursor, pOrderBy->nExpr+2, 0, + sSort.iECursor, sSort.pOrderBy->nExpr+2, 0, (char*)pKeyInfo, P4_KEYINFO); }else{ - addrSortIndex = -1; + sSort.addrSortIndex = -1; } /* If the output is destined for a temporary table, open that table. @@ -104750,9 +106221,9 @@ SQLITE_PRIVATE int sqlite3Select( iEnd = sqlite3VdbeMakeLabel(v); p->nSelectRow = LARGEST_INT64; computeLimitRegisters(pParse, p, iEnd); - if( p->iLimit==0 && addrSortIndex>=0 ){ - sqlite3VdbeGetOp(v, addrSortIndex)->opcode = OP_SorterOpen; - p->selFlags |= SF_UseSorter; + if( p->iLimit==0 && sSort.addrSortIndex>=0 ){ + sqlite3VdbeGetOp(v, sSort.addrSortIndex)->opcode = OP_SorterOpen; + sSort.sortFlags |= SORTFLAG_UseSorter; } /* Open a virtual index to use for the distinct set. @@ -104761,7 +106232,7 @@ SQLITE_PRIVATE int sqlite3Select( sDistinct.tabTnct = pParse->nTab++; sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, sDistinct.tabTnct, 0, 0, - (char*)keyInfoFromExprList(pParse, p->pEList, 0), + (char*)keyInfoFromExprList(pParse, p->pEList,0,0), P4_KEYINFO); sqlite3VdbeChangeP5(v, BTREE_UNORDERED); sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED; @@ -104774,8 +106245,8 @@ SQLITE_PRIVATE int sqlite3Select( u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0); /* Begin the database scan. */ - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pOrderBy, p->pEList, - wctrlFlags, 0); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy, + p->pEList, wctrlFlags, 0); if( pWInfo==0 ) goto select_end; if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){ p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo); @@ -104783,19 +106254,23 @@ SQLITE_PRIVATE int sqlite3Select( if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){ sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo); } - if( pOrderBy && sqlite3WhereIsOrdered(pWInfo) ) pOrderBy = 0; + if( sSort.pOrderBy ){ + sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo); + if( sSort.nOBSat==sSort.pOrderBy->nExpr ){ + sSort.pOrderBy = 0; + } + } /* If sorting index that was created by a prior OP_OpenEphemeral ** instruction ended up not being needed, then change the OP_OpenEphemeral ** into an OP_Noop. */ - if( addrSortIndex>=0 && pOrderBy==0 ){ - sqlite3VdbeChangeToNoop(v, addrSortIndex); - p->addrOpenEphm[2] = -1; + if( sSort.addrSortIndex>=0 && sSort.pOrderBy==0 ){ + sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex); } /* Use the standard inner loop. */ - selectInnerLoop(pParse, p, pEList, -1, pOrderBy, &sDistinct, pDest, + selectInnerLoop(pParse, p, pEList, -1, &sSort, &sDistinct, pDest, sqlite3WhereContinueLabel(pWInfo), sqlite3WhereBreakLabel(pWInfo)); @@ -104816,6 +106291,7 @@ SQLITE_PRIVATE int sqlite3Select( int addrEnd; /* End of processing for this SELECT */ int sortPTab = 0; /* Pseudotable used to decode sorting results */ int sortOut = 0; /* Output register from the sorter */ + int orderByGrp = 0; /* True if the GROUP BY and ORDER BY are the same */ /* Remove any and all aliases between the result set and the ** GROUP BY clause. @@ -104835,6 +106311,18 @@ SQLITE_PRIVATE int sqlite3Select( p->nSelectRow = 1; } + + /* If there is both a GROUP BY and an ORDER BY clause and they are + ** identical, then it may be possible to disable the ORDER BY clause + ** on the grounds that the GROUP BY will cause elements to come out + ** in the correct order. It also may not - the GROUP BY may use a + ** database index that causes rows to be grouped together as required + ** but not actually sorted. Either way, record the fact that the + ** ORDER BY and GROUP BY clauses are the same by setting the orderByGrp + ** variable. */ + if( sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 ){ + orderByGrp = 1; + } /* Create a label to jump to when we want to abort the query */ addrEnd = sqlite3VdbeMakeLabel(v); @@ -104851,7 +106339,7 @@ SQLITE_PRIVATE int sqlite3Select( sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0; sAggInfo.pGroupBy = pGroupBy; sqlite3ExprAnalyzeAggList(&sNC, pEList); - sqlite3ExprAnalyzeAggList(&sNC, pOrderBy); + sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy); if( pHaving ){ sqlite3ExprAnalyzeAggregates(&sNC, pHaving); } @@ -104885,7 +106373,7 @@ SQLITE_PRIVATE int sqlite3Select( ** will be converted into a Noop. */ sAggInfo.sortingIdx = pParse->nTab++; - pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0); + pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, 0); addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen, sAggInfo.sortingIdx, sAggInfo.nSortingColumn, 0, (char*)pKeyInfo, P4_KEYINFO); @@ -104914,10 +106402,11 @@ SQLITE_PRIVATE int sqlite3Select( ** in the right order to begin with. */ sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0, - WHERE_GROUPBY, 0); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0, + WHERE_GROUPBY | (orderByGrp ? WHERE_SORTBYGROUP : 0), 0 + ); if( pWInfo==0 ) goto select_end; - if( sqlite3WhereIsOrdered(pWInfo) ){ + if( sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){ /* The optimizer is able to deliver rows in group by order so ** we do not have to sort. The OP_OpenEphemeral table will be ** cancelled later because we still need to use the pKeyInfo @@ -104980,6 +106469,21 @@ SQLITE_PRIVATE int sqlite3Select( VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v); sAggInfo.useSortingIdx = 1; sqlite3ExprCacheClear(pParse); + + } + + /* If the index or temporary table used by the GROUP BY sort + ** will naturally deliver rows in the order required by the ORDER BY + ** clause, cancel the ephemeral table open coded earlier. + ** + ** This is an optimization - the correct answer should result regardless. + ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER to + ** disable this optimization for testing purposes. */ + if( orderByGrp && OptimizationEnabled(db, SQLITE_GroupByOrder) + && (groupBySort || sqlite3WhereIsSorted(pWInfo)) + ){ + sSort.pOrderBy = 0; + sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex); } /* Evaluate the current GROUP BY terms and store in b0, b1, b2... @@ -105068,7 +106572,7 @@ SQLITE_PRIVATE int sqlite3Select( sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); finalizeAggFunctions(pParse, &sAggInfo); sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL); - selectInnerLoop(pParse, p, p->pEList, -1, pOrderBy, + selectInnerLoop(pParse, p, p->pEList, -1, &sSort, &sDistinct, pDest, addrOutputRow+1, addrSetAbort); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); @@ -105200,7 +106704,7 @@ SQLITE_PRIVATE int sqlite3Select( } updateAccumulator(pParse, &sAggInfo); assert( pMinMax==0 || pMinMax->nExpr==1 ); - if( sqlite3WhereIsOrdered(pWInfo) ){ + if( sqlite3WhereIsOrdered(pWInfo)>0 ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3WhereBreakLabel(pWInfo)); VdbeComment((v, "%s() by index", (flag==WHERE_ORDERBY_MIN?"min":"max"))); @@ -105209,7 +106713,7 @@ SQLITE_PRIVATE int sqlite3Select( finalizeAggFunctions(pParse, &sAggInfo); } - pOrderBy = 0; + sSort.pOrderBy = 0; sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL); selectInnerLoop(pParse, p, p->pEList, -1, 0, 0, pDest, addrEnd, addrEnd); @@ -105226,9 +106730,9 @@ SQLITE_PRIVATE int sqlite3Select( /* If there is an ORDER BY clause, then we need to sort the results ** and send them to the callback one by one. */ - if( pOrderBy ){ - explainTempTable(pParse, "ORDER BY"); - generateSortTail(pParse, p, v, pEList->nExpr, pDest); + if( sSort.pOrderBy ){ + explainTempTable(pParse, sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY"); + generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest); } /* Jump here to skip this query @@ -106867,7 +108371,7 @@ SQLITE_PRIVATE void sqlite3Update( iIdxCur = iDataCur+1; pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ - if( pIdx->autoIndex==2 && pPk!=0 ){ + if( IsPrimaryKeyIndex(pIdx) && pPk!=0 ){ iDataCur = pParse->nTab; pTabList->a[0].iCursor = iDataCur; } @@ -107118,7 +108622,8 @@ SQLITE_PRIVATE void sqlite3Update( } labelContinue = labelBreak; sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak); - VdbeCoverage(v); + VdbeCoverageIf(v, pPk==0); + VdbeCoverageIf(v, pPk!=0); }else if( pPk ){ labelContinue = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v); @@ -109066,7 +110571,7 @@ struct WhereLoop { struct { /* Information for virtual tables */ int idxNum; /* Index number */ u8 needFree; /* True if sqlite3_free(idxStr) is needed */ - u8 isOrdered; /* True if satisfies ORDER BY */ + i8 isOrdered; /* True if satisfies ORDER BY */ u16 omitMask; /* Terms that may be omitted */ char *idxStr; /* Index identifier string */ } vtab; @@ -109128,8 +110633,8 @@ struct WherePath { Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */ LogEst nRow; /* Estimated number of rows generated by this path */ LogEst rCost; /* Total cost of this path */ - u8 isOrdered; /* True if this path satisfies ORDER BY */ - u8 isOrderedValid; /* True if the isOrdered field is valid */ + LogEst rUnsorted; /* Total cost of this path ignoring sorting costs */ + i8 isOrdered; /* No. of ORDER BY terms satisfied. -1 for unknown */ WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */ }; @@ -109343,7 +110848,8 @@ struct WhereInfo { Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ LogEst nRowOut; /* Estimated number of output rows */ u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ - u8 bOBSat; /* ORDER BY satisfied by indices */ + i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */ + u8 sorted; /* True if really sorted (not just grouped) */ u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */ u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */ @@ -109427,7 +110933,7 @@ SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo *pWInfo){ ** Return FALSE if the output needs to be sorted. */ SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){ - return pWInfo->bOBSat!=0; + return pWInfo->nOBSat; } /* @@ -109435,6 +110941,7 @@ SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){ ** immediately with the next row of a WHERE clause. */ SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo *pWInfo){ + assert( pWInfo->iContinue!=0 ); return pWInfo->iContinue; } @@ -109614,7 +111121,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){ if( p && ExprHasProperty(p, EP_Unlikely) ){ pTerm->truthProb = sqlite3LogEst(p->iTable) - 99; }else{ - pTerm->truthProb = -1; + pTerm->truthProb = 1; } pTerm->pExpr = sqlite3ExprSkipCollate(p); pTerm->wtFlags = wtFlags; @@ -109931,7 +111438,7 @@ static WhereTerm *whereScanInit( if( pIdx && iColumn>=0 ){ pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity; for(j=0; pIdx->aiColumn[j]!=iColumn; j++){ - if( NEVER(j>=pIdx->nKeyCol) ) return 0; + if( NEVER(j>pIdx->nColumn) ) return 0; } pScan->zCollName = pIdx->azColl[j]; }else{ @@ -110857,7 +112364,7 @@ static int isDistinctRedundant( ** contain a "col=X" term are subject to a NOT NULL constraint. */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->onError==OE_None ) continue; + if( !IsUniqueIndex(pIdx) ) continue; for(i=0; inKeyCol; i++){ i16 iCol = pIdx->aiColumn[i]; if( 0==findTerm(pWC, iBase, iCol, ~(Bitmask)0, WO_EQ, pIdx) ){ @@ -110881,8 +112388,7 @@ static int isDistinctRedundant( ** Estimate the logarithm of the input value to base 2. */ static LogEst estLog(LogEst N){ - LogEst x = sqlite3LogEst(N); - return x>33 ? x - 33 : 0; + return N<=10 ? 0 : sqlite3LogEst(N) - 33; } /* @@ -111343,10 +112849,11 @@ static void whereKeyStats( iLower = 0; iUpper = aSample[0].anLt[iCol]; }else{ - iUpper = i>=pIdx->nSample ? pIdx->aiRowEst[0] : aSample[i].anLt[iCol]; + i64 nRow0 = sqlite3LogEstToInt(pIdx->aiRowLogEst[0]); + iUpper = i>=pIdx->nSample ? nRow0 : aSample[i].anLt[iCol]; iLower = aSample[i-1].anEq[iCol] + aSample[i-1].anLt[iCol]; } - aStat[1] = (pIdx->nKeyCol>iCol ? pIdx->aAvgEq[iCol] : 1); + aStat[1] = pIdx->aAvgEq[iCol]; if( iLower>=iUpper ){ iGap = 0; }else{ @@ -111362,6 +112869,138 @@ static void whereKeyStats( } #endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ +/* +** If it is not NULL, pTerm is a term that provides an upper or lower +** bound on a range scan. Without considering pTerm, it is estimated +** that the scan will visit nNew rows. This function returns the number +** estimated to be visited after taking pTerm into account. +** +** If the user explicitly specified a likelihood() value for this term, +** then the return value is the likelihood multiplied by the number of +** input rows. Otherwise, this function assumes that an "IS NOT NULL" term +** has a likelihood of 0.50, and any other term a likelihood of 0.25. +*/ +static LogEst whereRangeAdjust(WhereTerm *pTerm, LogEst nNew){ + LogEst nRet = nNew; + if( pTerm ){ + if( pTerm->truthProb<=0 ){ + nRet += pTerm->truthProb; + }else if( (pTerm->wtFlags & TERM_VNULL)==0 ){ + nRet -= 20; assert( 20==sqlite3LogEst(4) ); + } + } + return nRet; +} + +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +/* +** This function is called to estimate the number of rows visited by a +** range-scan on a skip-scan index. For example: +** +** CREATE INDEX i1 ON t1(a, b, c); +** SELECT * FROM t1 WHERE a=? AND c BETWEEN ? AND ?; +** +** Value pLoop->nOut is currently set to the estimated number of rows +** visited for scanning (a=? AND b=?). This function reduces that estimate +** by some factor to account for the (c BETWEEN ? AND ?) expression based +** on the stat4 data for the index. this scan will be peformed multiple +** times (once for each (a,b) combination that matches a=?) is dealt with +** by the caller. +** +** It does this by scanning through all stat4 samples, comparing values +** extracted from pLower and pUpper with the corresponding column in each +** sample. If L and U are the number of samples found to be less than or +** equal to the values extracted from pLower and pUpper respectively, and +** N is the total number of samples, the pLoop->nOut value is adjusted +** as follows: +** +** nOut = nOut * ( min(U - L, 1) / N ) +** +** If pLower is NULL, or a value cannot be extracted from the term, L is +** set to zero. If pUpper is NULL, or a value cannot be extracted from it, +** U is set to N. +** +** Normally, this function sets *pbDone to 1 before returning. However, +** if no value can be extracted from either pLower or pUpper (and so the +** estimate of the number of rows delivered remains unchanged), *pbDone +** is left as is. +** +** If an error occurs, an SQLite error code is returned. Otherwise, +** SQLITE_OK. +*/ +static int whereRangeSkipScanEst( + Parse *pParse, /* Parsing & code generating context */ + WhereTerm *pLower, /* Lower bound on the range. ex: "x>123" Might be NULL */ + WhereTerm *pUpper, /* Upper bound on the range. ex: "x<455" Might be NULL */ + WhereLoop *pLoop, /* Update the .nOut value of this loop */ + int *pbDone /* Set to true if at least one expr. value extracted */ +){ + Index *p = pLoop->u.btree.pIndex; + int nEq = pLoop->u.btree.nEq; + sqlite3 *db = pParse->db; + int nLower = -1; + int nUpper = p->nSample+1; + int rc = SQLITE_OK; + int iCol = p->aiColumn[nEq]; + u8 aff = iCol>=0 ? p->pTable->aCol[iCol].affinity : SQLITE_AFF_INTEGER; + CollSeq *pColl; + + sqlite3_value *p1 = 0; /* Value extracted from pLower */ + sqlite3_value *p2 = 0; /* Value extracted from pUpper */ + sqlite3_value *pVal = 0; /* Value extracted from record */ + + pColl = sqlite3LocateCollSeq(pParse, p->azColl[nEq]); + if( pLower ){ + rc = sqlite3Stat4ValueFromExpr(pParse, pLower->pExpr->pRight, aff, &p1); + nLower = 0; + } + if( pUpper && rc==SQLITE_OK ){ + rc = sqlite3Stat4ValueFromExpr(pParse, pUpper->pExpr->pRight, aff, &p2); + nUpper = p2 ? 0 : p->nSample; + } + + if( p1 || p2 ){ + int i; + int nDiff; + for(i=0; rc==SQLITE_OK && inSample; i++){ + rc = sqlite3Stat4Column(db, p->aSample[i].p, p->aSample[i].n, nEq, &pVal); + if( rc==SQLITE_OK && p1 ){ + int res = sqlite3MemCompare(p1, pVal, pColl); + if( res>=0 ) nLower++; + } + if( rc==SQLITE_OK && p2 ){ + int res = sqlite3MemCompare(p2, pVal, pColl); + if( res>=0 ) nUpper++; + } + } + nDiff = (nUpper - nLower); + if( nDiff<=0 ) nDiff = 1; + + /* If there is both an upper and lower bound specified, and the + ** comparisons indicate that they are close together, use the fallback + ** method (assume that the scan visits 1/64 of the rows) for estimating + ** the number of rows visited. Otherwise, estimate the number of rows + ** using the method described in the header comment for this function. */ + if( nDiff!=1 || pUpper==0 || pLower==0 ){ + int nAdjust = (sqlite3LogEst(p->nSample) - sqlite3LogEst(nDiff)); + pLoop->nOut -= nAdjust; + *pbDone = 1; + WHERETRACE(0x10, ("range skip-scan regions: %u..%u adjust=%d est=%d\n", + nLower, nUpper, nAdjust*-1, pLoop->nOut)); + } + + }else{ + assert( *pbDone==0 ); + } + + sqlite3ValueFree(p1); + sqlite3ValueFree(p2); + sqlite3ValueFree(pVal); + + return rc; +} +#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ + /* ** This function is used to estimate the number of rows that will be visited ** by scanning an index for a range of values. The range may have an upper @@ -111398,9 +113037,9 @@ static void whereKeyStats( ** to account for the range contraints pLower and pUpper. ** ** In the absence of sqlite_stat4 ANALYZE data, or if such data cannot be -** used, each range inequality reduces the search space by a factor of 4. -** Hence a pair of constraints (x>? AND x? AND xu.btree.nEq; if( p->nSample>0 - && nEq==pBuilder->nRecValid && nEqnSampleCol && OptimizationEnabled(pParse->db, SQLITE_Stat3) ){ - UnpackedRecord *pRec = pBuilder->pRec; - tRowcnt a[2]; - u8 aff; + if( nEq==pBuilder->nRecValid ){ + UnpackedRecord *pRec = pBuilder->pRec; + tRowcnt a[2]; + u8 aff; - /* Variable iLower will be set to the estimate of the number of rows in - ** the index that are less than the lower bound of the range query. The - ** lower bound being the concatenation of $P and $L, where $P is the - ** key-prefix formed by the nEq values matched against the nEq left-most - ** columns of the index, and $L is the value in pLower. - ** - ** Or, if pLower is NULL or $L cannot be extracted from it (because it - ** is not a simple variable or literal value), the lower bound of the - ** range is $P. Due to a quirk in the way whereKeyStats() works, even - ** if $L is available, whereKeyStats() is called for both ($P) and - ** ($P:$L) and the larger of the two returned values used. - ** - ** Similarly, iUpper is to be set to the estimate of the number of rows - ** less than the upper bound of the range query. Where the upper bound - ** is either ($P) or ($P:$U). Again, even if $U is available, both values - ** of iUpper are requested of whereKeyStats() and the smaller used. - */ - tRowcnt iLower; - tRowcnt iUpper; + /* Variable iLower will be set to the estimate of the number of rows in + ** the index that are less than the lower bound of the range query. The + ** lower bound being the concatenation of $P and $L, where $P is the + ** key-prefix formed by the nEq values matched against the nEq left-most + ** columns of the index, and $L is the value in pLower. + ** + ** Or, if pLower is NULL or $L cannot be extracted from it (because it + ** is not a simple variable or literal value), the lower bound of the + ** range is $P. Due to a quirk in the way whereKeyStats() works, even + ** if $L is available, whereKeyStats() is called for both ($P) and + ** ($P:$L) and the larger of the two returned values used. + ** + ** Similarly, iUpper is to be set to the estimate of the number of rows + ** less than the upper bound of the range query. Where the upper bound + ** is either ($P) or ($P:$U). Again, even if $U is available, both values + ** of iUpper are requested of whereKeyStats() and the smaller used. + */ + tRowcnt iLower; + tRowcnt iUpper; - if( nEq==p->nKeyCol ){ - aff = SQLITE_AFF_INTEGER; - }else{ - aff = p->pTable->aCol[p->aiColumn[nEq]].affinity; - } - /* Determine iLower and iUpper using ($P) only. */ - if( nEq==0 ){ - iLower = 0; - iUpper = p->aiRowEst[0]; - }else{ - /* Note: this call could be optimized away - since the same values must - ** have been requested when testing key $P in whereEqualScanEst(). */ - whereKeyStats(pParse, p, pRec, 0, a); - iLower = a[0]; - iUpper = a[0] + a[1]; - } - - /* If possible, improve on the iLower estimate using ($P:$L). */ - if( pLower ){ - int bOk; /* True if value is extracted from pExpr */ - Expr *pExpr = pLower->pExpr->pRight; - assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 ); - rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); - if( rc==SQLITE_OK && bOk ){ - tRowcnt iNew; - whereKeyStats(pParse, p, pRec, 0, a); - iNew = a[0] + ((pLower->eOperator & WO_GT) ? a[1] : 0); - if( iNew>iLower ) iLower = iNew; - nOut--; - } - } - - /* If possible, improve on the iUpper estimate using ($P:$U). */ - if( pUpper ){ - int bOk; /* True if value is extracted from pExpr */ - Expr *pExpr = pUpper->pExpr->pRight; - assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 ); - rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); - if( rc==SQLITE_OK && bOk ){ - tRowcnt iNew; - whereKeyStats(pParse, p, pRec, 1, a); - iNew = a[0] + ((pUpper->eOperator & WO_LE) ? a[1] : 0); - if( iNewpRec = pRec; - if( rc==SQLITE_OK ){ - if( iUpper>iLower ){ - nNew = sqlite3LogEst(iUpper - iLower); + if( nEq==p->nKeyCol ){ + aff = SQLITE_AFF_INTEGER; }else{ - nNew = 10; assert( 10==sqlite3LogEst(2) ); + aff = p->pTable->aCol[p->aiColumn[nEq]].affinity; } - if( nNewaiRowLogEst[0]); + }else{ + /* Note: this call could be optimized away - since the same values must + ** have been requested when testing key $P in whereEqualScanEst(). */ + whereKeyStats(pParse, p, pRec, 0, a); + iLower = a[0]; + iUpper = a[0] + a[1]; } - pLoop->nOut = (LogEst)nOut; - WHERETRACE(0x10, ("range scan regions: %u..%u est=%d\n", - (u32)iLower, (u32)iUpper, nOut)); - return SQLITE_OK; + + /* If possible, improve on the iLower estimate using ($P:$L). */ + if( pLower ){ + int bOk; /* True if value is extracted from pExpr */ + Expr *pExpr = pLower->pExpr->pRight; + assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 ); + rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); + if( rc==SQLITE_OK && bOk ){ + tRowcnt iNew; + whereKeyStats(pParse, p, pRec, 0, a); + iNew = a[0] + ((pLower->eOperator & WO_GT) ? a[1] : 0); + if( iNew>iLower ) iLower = iNew; + nOut--; + } + } + + /* If possible, improve on the iUpper estimate using ($P:$U). */ + if( pUpper ){ + int bOk; /* True if value is extracted from pExpr */ + Expr *pExpr = pUpper->pExpr->pRight; + assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 ); + rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); + if( rc==SQLITE_OK && bOk ){ + tRowcnt iNew; + whereKeyStats(pParse, p, pRec, 1, a); + iNew = a[0] + ((pUpper->eOperator & WO_LE) ? a[1] : 0); + if( iNewpRec = pRec; + if( rc==SQLITE_OK ){ + if( iUpper>iLower ){ + nNew = sqlite3LogEst(iUpper - iLower); + }else{ + nNew = 10; assert( 10==sqlite3LogEst(2) ); + } + if( nNewnOut = (LogEst)nOut; + WHERETRACE(0x10, ("range scan regions: %u..%u est=%d\n", + (u32)iLower, (u32)iUpper, nOut)); + return SQLITE_OK; + } + }else{ + int bDone = 0; + rc = whereRangeSkipScanEst(pParse, pLower, pUpper, pLoop, &bDone); + if( bDone ) return rc; } } #else @@ -111514,17 +113158,18 @@ static int whereRangeScanEst( UNUSED_PARAMETER(pBuilder); #endif assert( pLower || pUpper ); - /* TUNING: Each inequality constraint reduces the search space 4-fold. - ** A BETWEEN operator, therefore, reduces the search space 16-fold */ - nNew = nOut; - if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ){ - nNew -= 20; assert( 20==sqlite3LogEst(4) ); - nOut--; - } - if( pUpper ){ - nNew -= 20; assert( 20==sqlite3LogEst(4) ); - nOut--; - } + assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 ); + nNew = whereRangeAdjust(pLower, nOut); + nNew = whereRangeAdjust(pUpper, nNew); + + /* TUNING: If there is both an upper and lower limit, assume the range is + ** reduced by an additional 75%. This means that, by default, an open-ended + ** range query (e.g. col > ?) is assumed to match 1/4 of the rows in the + ** index. While a closed range (e.g. col BETWEEN ? AND ?) is estimated to + ** match 1/64 of the index. */ + if( pLower && pUpper ) nNew -= 20; + + nOut -= (pLower!=0) + (pUpper!=0); if( nNew<10 ) nNew = 10; if( nNewnOut = (LogEst)nOut; @@ -111564,7 +113209,7 @@ static int whereEqualScanEst( int bOk; assert( nEq>=1 ); - assert( nEq<=(p->nKeyCol+1) ); + assert( nEq<=p->nColumn ); assert( p->aSample!=0 ); assert( p->nSample>0 ); assert( pBuilder->nRecValidp->nKeyCol ){ + if( nEq>=p->nColumn ){ *pnRow = 1; return SQLITE_OK; } @@ -111621,6 +113266,7 @@ static int whereInScanEst( tRowcnt *pnRow /* Write the revised row estimate here */ ){ Index *p = pBuilder->pNew->u.btree.pIndex; + i64 nRow0 = sqlite3LogEstToInt(p->aiRowLogEst[0]); int nRecValid = pBuilder->nRecValid; int rc = SQLITE_OK; /* Subfunction return code */ tRowcnt nEst; /* Number of rows for a single term */ @@ -111629,14 +113275,14 @@ static int whereInScanEst( assert( p->aSample!=0 ); for(i=0; rc==SQLITE_OK && inExpr; i++){ - nEst = p->aiRowEst[0]; + nEst = nRow0; rc = whereEqualScanEst(pParse, pBuilder, pList->a[i].pExpr, &nEst); nRowEst += nEst; pBuilder->nRecValid = nRecValid; } if( rc==SQLITE_OK ){ - if( nRowEst > p->aiRowEst[0] ) nRowEst = p->aiRowEst[0]; + if( nRowEst > nRow0 ) nRowEst = nRow0; *pnRow = nRowEst; WHERETRACE(0x10,("IN row estimate: est=%g\n", nRowEst)); } @@ -111770,7 +113416,7 @@ static int codeEqualityTerm( } assert( pX->op==TK_IN ); iReg = iTarget; - eType = sqlite3FindInIndex(pParse, pX, 0); + eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0); if( eType==IN_INDEX_INDEX_DESC ){ testcase( bRev ); bRev = !bRev; @@ -112007,7 +113653,7 @@ static char *explainIndexRange(sqlite3 *db, WhereLoop *pLoop, Table *pTab){ txt.db = db; sqlite3StrAccumAppend(&txt, " (", 2); for(i=0; inKeyCol ) ? "rowid" : aCol[aiColumn[i]].zName; + char *z = aiColumn[i] < 0 ? "rowid" : aCol[aiColumn[i]].zName; if( i>=nSkip ){ explainAppendTerm(&txt, i, z, "="); }else{ @@ -112020,11 +113666,11 @@ static char *explainIndexRange(sqlite3 *db, WhereLoop *pLoop, Table *pTab){ j = i; if( pLoop->wsFlags&WHERE_BTM_LIMIT ){ - char *z = (j==pIndex->nKeyCol ) ? "rowid" : aCol[aiColumn[j]].zName; + char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName; explainAppendTerm(&txt, i++, z, ">"); } if( pLoop->wsFlags&WHERE_TOP_LIMIT ){ - char *z = (j==pIndex->nKeyCol ) ? "rowid" : aCol[aiColumn[j]].zName; + char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName; explainAppendTerm(&txt, i, z, "<"); } sqlite3StrAccumAppend(&txt, ")", 1); @@ -112079,13 +113725,20 @@ static void explainOneScan( if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 && ALWAYS(pLoop->u.btree.pIndex!=0) ){ + const char *zFmt; + Index *pIdx = pLoop->u.btree.pIndex; char *zWhere = explainIndexRange(db, pLoop, pItem->pTab); - zMsg = sqlite3MAppendf(db, zMsg, - ((flags & WHERE_AUTO_INDEX) ? - "%s USING AUTOMATIC %sINDEX%.0s%s" : - "%s USING %sINDEX %s%s"), - zMsg, ((flags & WHERE_IDX_ONLY) ? "COVERING " : ""), - pLoop->u.btree.pIndex->zName, zWhere); + assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) ); + if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){ + zFmt = zWhere ? "%s USING PRIMARY KEY%.0s%s" : "%s%.0s%s"; + }else if( flags & WHERE_AUTO_INDEX ){ + zFmt = "%s USING AUTOMATIC COVERING INDEX%.0s%s"; + }else if( flags & WHERE_IDX_ONLY ){ + zFmt = "%s USING COVERING INDEX %s%s"; + }else{ + zFmt = "%s USING INDEX %s%s"; + } + zMsg = sqlite3MAppendf(db, zMsg, zFmt, zMsg, pIdx->zName, zWhere); sqlite3DbFree(db, zWhere); }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){ zMsg = sqlite3MAppendf(db, zMsg, "%s USING INTEGER PRIMARY KEY", zMsg); @@ -112228,7 +113881,7 @@ static Bitmask codeOneLoopStart( pLevel->p1 = iCur; pLevel->p2 = sqlite3VdbeCurrentAddr(v); sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); - sqlite3ExprCachePop(pParse, 1); + sqlite3ExprCachePop(pParse); }else #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -112424,8 +114077,11 @@ static Bitmask codeOneLoopStart( ** the first one after the nEq equality constraints in the index, ** this requires some special handling. */ + assert( pWInfo->pOrderBy==0 + || pWInfo->pOrderBy->nExpr==1 + || (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 ); if( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0 - && (pWInfo->bOBSat!=0) + && pWInfo->nOBSat>0 && (pIdx->nKeyCol>nEq) ){ assert( pLoop->u.btree.nSkip==0 ); @@ -112574,7 +114230,7 @@ static Bitmask codeOneLoopStart( sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg); sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); sqlite3VdbeAddOp2(v, OP_Seek, iCur, iRowidReg); /* Deferred seek */ - }else{ + }else if( iCur!=iIdxCur ){ Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol); for(j=0; jnKeyCol; j++){ @@ -112596,8 +114252,7 @@ static Bitmask codeOneLoopStart( pLevel->op = OP_Next; } pLevel->p1 = iIdxCur; - assert( (WHERE_UNQ_WANTED>>16)==1 ); - pLevel->p3 = (pLoop->wsFlags>>16)&1; + pLevel->p3 = (pLoop->wsFlags&WHERE_UNQ_WANTED)!=0 ? 1:0; if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){ pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; }else{ @@ -112645,6 +114300,10 @@ static Bitmask codeOneLoopStart( ** ** B: ** + ** Added 2014-05-26: If the table is a WITHOUT ROWID table, then + ** use an ephermeral index instead of a RowSet to record the primary + ** keys of the rows we have already seen. + ** */ WhereClause *pOrWc; /* The OR-clause broken out into subterms */ SrcList *pOrTab; /* Shortened table list or OR-clause generation */ @@ -112658,7 +114317,9 @@ static Bitmask codeOneLoopStart( int iRetInit; /* Address of regReturn init */ int untestedTerms = 0; /* Some terms not completely tested */ int ii; /* Loop counter */ + u16 wctrlFlags; /* Flags for sub-WHERE clause */ Expr *pAndExpr = 0; /* An ".. AND (...)" expression */ + Table *pTab = pTabItem->pTab; pTerm = pLoop->aLTerm[0]; assert( pTerm!=0 ); @@ -112691,7 +114352,8 @@ static Bitmask codeOneLoopStart( } /* Initialize the rowset register to contain NULL. An SQL NULL is - ** equivalent to an empty rowset. + ** equivalent to an empty rowset. Or, create an ephermeral index + ** capable of holding primary keys in the case of a WITHOUT ROWID. ** ** Also initialize regReturn to contain the address of the instruction ** immediately following the OP_Return at the bottom of the loop. This @@ -112702,9 +114364,16 @@ static Bitmask codeOneLoopStart( ** called on an uninitialized cursor. */ if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ - regRowset = ++pParse->nMem; + if( HasRowid(pTab) ){ + regRowset = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset); + }else{ + Index *pPk = sqlite3PrimaryKeyIndex(pTab); + regRowset = pParse->nTab++; + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, regRowset, pPk->nKeyCol); + sqlite3VdbeSetP4KeyInfo(pParse, pPk); + } regRowid = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset); } iRetInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, regReturn); @@ -112740,36 +114409,88 @@ static Bitmask codeOneLoopStart( } } + /* Run a separate WHERE clause for each term of the OR clause. After + ** eliminating duplicates from other WHERE clauses, the action for each + ** sub-WHERE clause is to to invoke the main loop body as a subroutine. + */ + wctrlFlags = WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY | + WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY; for(ii=0; iinTerm; ii++){ WhereTerm *pOrTerm = &pOrWc->a[ii]; if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ - WhereInfo *pSubWInfo; /* Info for single OR-term scan */ - Expr *pOrExpr = pOrTerm->pExpr; + WhereInfo *pSubWInfo; /* Info for single OR-term scan */ + Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */ + int j1 = 0; /* Address of jump operation */ if( pAndExpr && !ExprHasProperty(pOrExpr, EP_FromJoin) ){ pAndExpr->pLeft = pOrExpr; pOrExpr = pAndExpr; } /* Loop through table entries that match term pOrTerm. */ pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, - WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY | - WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY, iCovCur); + wctrlFlags, iCovCur); assert( pSubWInfo || pParse->nErr || db->mallocFailed ); if( pSubWInfo ){ WhereLoop *pSubLoop; explainOneScan( pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0 ); + /* This is the sub-WHERE clause body. First skip over + ** duplicate rows from prior sub-WHERE clauses, and record the + ** rowid (or PRIMARY KEY) for the current row so that the same + ** row will be skipped in subsequent sub-WHERE clauses. + */ if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ - int iSet = ((ii==pOrWc->nTerm-1)?-1:ii); int r; - r = sqlite3ExprCodeGetColumn(pParse, pTabItem->pTab, -1, iCur, - regRowid, 0); - sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, - sqlite3VdbeCurrentAddr(v)+2, r, iSet); - VdbeCoverage(v); + int iSet = ((ii==pOrWc->nTerm-1)?-1:ii); + if( HasRowid(pTab) ){ + r = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, regRowid, 0); + j1 = sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, 0, r,iSet); + VdbeCoverage(v); + }else{ + Index *pPk = sqlite3PrimaryKeyIndex(pTab); + int nPk = pPk->nKeyCol; + int iPk; + + /* Read the PK into an array of temp registers. */ + r = sqlite3GetTempRange(pParse, nPk); + for(iPk=0; iPkaiColumn[iPk]; + sqlite3ExprCodeGetColumn(pParse, pTab, iCol, iCur, r+iPk, 0); + } + + /* Check if the temp table already contains this key. If so, + ** the row has already been included in the result set and + ** can be ignored (by jumping past the Gosub below). Otherwise, + ** insert the key into the temp table and proceed with processing + ** the row. + ** + ** Use some of the same optimizations as OP_RowSetTest: If iSet + ** is zero, assume that the key cannot already be present in + ** the temp table. And if iSet is -1, assume that there is no + ** need to insert the key into the temp table, as it will never + ** be tested for. */ + if( iSet ){ + j1 = sqlite3VdbeAddOp4Int(v, OP_Found, regRowset, 0, r, nPk); + VdbeCoverage(v); + } + if( iSet>=0 ){ + sqlite3VdbeAddOp3(v, OP_MakeRecord, r, nPk, regRowid); + sqlite3VdbeAddOp3(v, OP_IdxInsert, regRowset, regRowid, 0); + if( iSet ) sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); + } + + /* Release the array of temp registers */ + sqlite3ReleaseTempRange(pParse, r, nPk); + } } + + /* Invoke the main loop body as a subroutine */ sqlite3VdbeAddOp2(v, OP_Gosub, regReturn, iLoopBody); + /* Jump here (skipping the main loop body subroutine) if the + ** current sub-WHERE row is a duplicate from prior sub-WHEREs. */ + if( j1 ) sqlite3VdbeJumpHere(v, j1); + /* The pSubWInfo->untestedTerms flag means that this OR term ** contained one or more AND term from a notReady table. The ** terms from the notReady table could not be tested and will @@ -112793,9 +114514,11 @@ static Bitmask codeOneLoopStart( assert( (pSubLoop->wsFlags & WHERE_AUTO_INDEX)==0 ); if( (pSubLoop->wsFlags & WHERE_INDEXED)!=0 && (ii==0 || pSubLoop->u.btree.pIndex==pCov) + && (HasRowid(pTab) || !IsPrimaryKeyIndex(pSubLoop->u.btree.pIndex)) ){ assert( pSubWInfo->a[0].iIdxCur==iCovCur ); pCov = pSubLoop->u.btree.pIndex; + wctrlFlags |= WHERE_REOPEN_IDX; }else{ pCov = 0; } @@ -112974,7 +114697,7 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){ sqlite3DebugPrintf(" %-19s", z); sqlite3_free(z); } - sqlite3DebugPrintf(" f %04x N %d", p->wsFlags, p->nLTerm); + sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm); sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut); #ifdef SQLITE_ENABLE_TREE_EXPLAIN /* If the 0x100 bit of wheretracing is set, then show all of the constraint @@ -113096,6 +114819,161 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ } } +/* +** Return TRUE if both of the following are true: +** +** (1) X has the same or lower cost that Y +** (2) X is a proper subset of Y +** +** By "proper subset" we mean that X uses fewer WHERE clause terms +** than Y and that every WHERE clause term used by X is also used +** by Y. +** +** If X is a proper subset of Y then Y is a better choice and ought +** to have a lower cost. This routine returns TRUE when that cost +** relationship is inverted and needs to be adjusted. +*/ +static int whereLoopCheaperProperSubset( + const WhereLoop *pX, /* First WhereLoop to compare */ + const WhereLoop *pY /* Compare against this WhereLoop */ +){ + int i, j; + if( pX->nLTerm >= pY->nLTerm ) return 0; /* X is not a subset of Y */ + if( pX->rRun >= pY->rRun ){ + if( pX->rRun > pY->rRun ) return 0; /* X costs more than Y */ + if( pX->nOut > pY->nOut ) return 0; /* X costs more than Y */ + } + for(i=pX->nLTerm-1; i>=0; i--){ + for(j=pY->nLTerm-1; j>=0; j--){ + if( pY->aLTerm[j]==pX->aLTerm[i] ) break; + } + if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */ + } + return 1; /* All conditions meet */ +} + +/* +** Try to adjust the cost of WhereLoop pTemplate upwards or downwards so +** that: +** +** (1) pTemplate costs less than any other WhereLoops that are a proper +** subset of pTemplate +** +** (2) pTemplate costs more than any other WhereLoops for which pTemplate +** is a proper subset. +** +** To say "WhereLoop X is a proper subset of Y" means that X uses fewer +** WHERE clause terms than Y and that every WHERE clause term used by X is +** also used by Y. +** +** This adjustment is omitted for SKIPSCAN loops. In a SKIPSCAN loop, the +** WhereLoop.nLTerm field is not an accurate measure of the number of WHERE +** clause terms covered, since some of the first nLTerm entries in aLTerm[] +** will be NULL (because they are skipped). That makes it more difficult +** to compare the loops. We could add extra code to do the comparison, and +** perhaps we will someday. But SKIPSCAN is sufficiently uncommon, and this +** adjustment is sufficient minor, that it is very difficult to construct +** a test case where the extra code would improve the query plan. Better +** to avoid the added complexity and just omit cost adjustments to SKIPSCAN +** loops. +*/ +static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){ + if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return; + if( (pTemplate->wsFlags & WHERE_SKIPSCAN)!=0 ) return; + for(; p; p=p->pNextLoop){ + if( p->iTab!=pTemplate->iTab ) continue; + if( (p->wsFlags & WHERE_INDEXED)==0 ) continue; + if( (p->wsFlags & WHERE_SKIPSCAN)!=0 ) continue; + if( whereLoopCheaperProperSubset(p, pTemplate) ){ + /* Adjust pTemplate cost downward so that it is cheaper than its + ** subset p */ + pTemplate->rRun = p->rRun; + pTemplate->nOut = p->nOut - 1; + }else if( whereLoopCheaperProperSubset(pTemplate, p) ){ + /* Adjust pTemplate cost upward so that it is costlier than p since + ** pTemplate is a proper subset of p */ + pTemplate->rRun = p->rRun; + pTemplate->nOut = p->nOut + 1; + } + } +} + +/* +** Search the list of WhereLoops in *ppPrev looking for one that can be +** supplanted by pTemplate. +** +** Return NULL if the WhereLoop list contains an entry that can supplant +** pTemplate, in other words if pTemplate does not belong on the list. +** +** If pX is a WhereLoop that pTemplate can supplant, then return the +** link that points to pX. +** +** If pTemplate cannot supplant any existing element of the list but needs +** to be added to the list, then return a pointer to the tail of the list. +*/ +static WhereLoop **whereLoopFindLesser( + WhereLoop **ppPrev, + const WhereLoop *pTemplate +){ + WhereLoop *p; + for(p=(*ppPrev); p; ppPrev=&p->pNextLoop, p=*ppPrev){ + if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ){ + /* If either the iTab or iSortIdx values for two WhereLoop are different + ** then those WhereLoops need to be considered separately. Neither is + ** a candidate to replace the other. */ + continue; + } + /* In the current implementation, the rSetup value is either zero + ** or the cost of building an automatic index (NlogN) and the NlogN + ** is the same for compatible WhereLoops. */ + assert( p->rSetup==0 || pTemplate->rSetup==0 + || p->rSetup==pTemplate->rSetup ); + + /* whereLoopAddBtree() always generates and inserts the automatic index + ** case first. Hence compatible candidate WhereLoops never have a larger + ** rSetup. Call this SETUP-INVARIANT */ + assert( p->rSetup>=pTemplate->rSetup ); + + /* Any loop using an appliation-defined index (or PRIMARY KEY or + ** UNIQUE constraint) with one or more == constraints is better + ** than an automatic index. */ + if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 + && (pTemplate->wsFlags & WHERE_INDEXED)!=0 + && (pTemplate->wsFlags & WHERE_COLUMN_EQ)!=0 + && (p->prereq & pTemplate->prereq)==pTemplate->prereq + ){ + break; + } + + /* If existing WhereLoop p is better than pTemplate, pTemplate can be + ** discarded. WhereLoop p is better if: + ** (1) p has no more dependencies than pTemplate, and + ** (2) p has an equal or lower cost than pTemplate + */ + if( (p->prereq & pTemplate->prereq)==p->prereq /* (1) */ + && p->rSetup<=pTemplate->rSetup /* (2a) */ + && p->rRun<=pTemplate->rRun /* (2b) */ + && p->nOut<=pTemplate->nOut /* (2c) */ + ){ + return 0; /* Discard pTemplate */ + } + + /* If pTemplate is always better than p, then cause p to be overwritten + ** with pTemplate. pTemplate is better than p if: + ** (1) pTemplate has no more dependences than p, and + ** (2) pTemplate has an equal or lower cost than p. + */ + if( (p->prereq & pTemplate->prereq)==pTemplate->prereq /* (1) */ + && p->rRun>=pTemplate->rRun /* (2a) */ + && p->nOut>=pTemplate->nOut /* (2b) */ + ){ + assert( p->rSetup>=pTemplate->rSetup ); /* SETUP-INVARIANT above */ + break; /* Cause p to be overwritten by pTemplate */ + } + } + return ppPrev; +} + /* ** Insert or replace a WhereLoop entry using the template supplied. ** @@ -113105,25 +114983,23 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ ** fewer dependencies than the template. Otherwise a new WhereLoop is ** added based on the template. ** -** If pBuilder->pOrSet is not NULL then we only care about only the +** If pBuilder->pOrSet is not NULL then we care about only the ** prerequisites and rRun and nOut costs of the N best loops. That ** information is gathered in the pBuilder->pOrSet object. This special ** processing mode is used only for OR clause processing. ** ** When accumulating multiple loops (when pBuilder->pOrSet is NULL) we ** still might overwrite similar loops with the new template if the -** template is better. Loops may be overwritten if the following +** new template is better. Loops may be overwritten if the following ** conditions are met: ** ** (1) They have the same iTab. ** (2) They have the same iSortIdx. ** (3) The template has same or fewer dependencies than the current loop ** (4) The template has the same or lower cost than the current loop -** (5) The template uses more terms of the same index but has no additional -** dependencies */ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ - WhereLoop **ppPrev, *p, *pNext = 0; + WhereLoop **ppPrev, *p; WhereInfo *pWInfo = pBuilder->pWInfo; sqlite3 *db = pWInfo->pParse->db; @@ -113146,64 +115022,23 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ return SQLITE_OK; } - /* Search for an existing WhereLoop to overwrite, or which takes - ** priority over pTemplate. + /* Look for an existing WhereLoop to replace with pTemplate */ - for(ppPrev=&pWInfo->pLoops, p=*ppPrev; p; ppPrev=&p->pNextLoop, p=*ppPrev){ - if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ){ - /* If either the iTab or iSortIdx values for two WhereLoop are different - ** then those WhereLoops need to be considered separately. Neither is - ** a candidate to replace the other. */ - continue; - } - /* In the current implementation, the rSetup value is either zero - ** or the cost of building an automatic index (NlogN) and the NlogN - ** is the same for compatible WhereLoops. */ - assert( p->rSetup==0 || pTemplate->rSetup==0 - || p->rSetup==pTemplate->rSetup ); + whereLoopAdjustCost(pWInfo->pLoops, pTemplate); + ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate); - /* whereLoopAddBtree() always generates and inserts the automatic index - ** case first. Hence compatible candidate WhereLoops never have a larger - ** rSetup. Call this SETUP-INVARIANT */ - assert( p->rSetup>=pTemplate->rSetup ); - - if( (p->prereq & pTemplate->prereq)==p->prereq - && p->rSetup<=pTemplate->rSetup - && p->rRun<=pTemplate->rRun - && p->nOut<=pTemplate->nOut - ){ - /* This branch taken when p is equal or better than pTemplate in - ** all of (1) dependencies (2) setup-cost, (3) run-cost, and - ** (4) number of output rows. */ - assert( p->rSetup==pTemplate->rSetup ); - if( p->prereq==pTemplate->prereq - && p->nLTermnLTerm - && (p->wsFlags & pTemplate->wsFlags & WHERE_INDEXED)!=0 - && (p->u.btree.pIndex==pTemplate->u.btree.pIndex - || pTemplate->rRun+p->nLTerm<=p->rRun+pTemplate->nLTerm) - ){ - /* Overwrite an existing WhereLoop with an similar one that uses - ** more terms of the index */ - pNext = p->pNextLoop; - break; - }else{ - /* pTemplate is not helpful. - ** Return without changing or adding anything */ - goto whereLoopInsert_noop; - } - } - if( (p->prereq & pTemplate->prereq)==pTemplate->prereq - && p->rRun>=pTemplate->rRun - && p->nOut>=pTemplate->nOut - ){ - /* Overwrite an existing WhereLoop with a better one: one that is - ** better at one of (1) dependencies, (2) setup-cost, (3) run-cost - ** or (4) number of output rows, and is no worse in any of those - ** categories. */ - assert( p->rSetup>=pTemplate->rSetup ); /* SETUP-INVARIANT above */ - pNext = p->pNextLoop; - break; + if( ppPrev==0 ){ + /* There already exists a WhereLoop on the list that is better + ** than pTemplate, so just ignore pTemplate */ +#if WHERETRACE_ENABLED /* 0x8 */ + if( sqlite3WhereTrace & 0x8 ){ + sqlite3DebugPrintf("ins-noop: "); + whereLoopPrint(pTemplate, pBuilder->pWC); } +#endif + return SQLITE_OK; + }else{ + p = *ppPrev; } /* If we reach this point it means that either p[] should be overwritten @@ -113221,13 +115056,33 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ } #endif if( p==0 ){ - p = sqlite3DbMallocRaw(db, sizeof(WhereLoop)); + /* Allocate a new WhereLoop to add to the end of the list */ + *ppPrev = p = sqlite3DbMallocRaw(db, sizeof(WhereLoop)); if( p==0 ) return SQLITE_NOMEM; whereLoopInit(p); + p->pNextLoop = 0; + }else{ + /* We will be overwriting WhereLoop p[]. But before we do, first + ** go through the rest of the list and delete any other entries besides + ** p[] that are also supplated by pTemplate */ + WhereLoop **ppTail = &p->pNextLoop; + WhereLoop *pToDel; + while( *ppTail ){ + ppTail = whereLoopFindLesser(ppTail, pTemplate); + if( ppTail==0 ) break; + pToDel = *ppTail; + if( pToDel==0 ) break; + *ppTail = pToDel->pNextLoop; +#if WHERETRACE_ENABLED /* 0x8 */ + if( sqlite3WhereTrace & 0x8 ){ + sqlite3DebugPrintf("ins-del: "); + whereLoopPrint(pToDel, pBuilder->pWC); + } +#endif + whereLoopDelete(db, pToDel); + } } whereLoopXfer(db, p, pTemplate); - p->pNextLoop = pNext; - *ppPrev = p; if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ Index *pIndex = p->u.btree.pIndex; if( pIndex && pIndex->tnum==0 ){ @@ -113235,16 +115090,6 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ } } return SQLITE_OK; - - /* Jump here if the insert is a no-op */ -whereLoopInsert_noop: -#if WHERETRACE_ENABLED /* 0x8 */ - if( sqlite3WhereTrace & 0x8 ){ - sqlite3DebugPrintf("ins-noop: "); - whereLoopPrint(pTemplate, pBuilder->pWC); - } -#endif - return SQLITE_OK; } /* @@ -113274,13 +115119,30 @@ static void whereLoopOutputAdjust(WhereClause *pWC, WhereLoop *pLoop){ if( pX==pTerm ) break; if( pX->iParent>=0 && (&pWC->a[pX->iParent])==pTerm ) break; } - if( j<0 ) pLoop->nOut += pTerm->truthProb; + if( j<0 ){ + pLoop->nOut += (pTerm->truthProb<=0 ? pTerm->truthProb : -1); + } } } /* -** We have so far matched pBuilder->pNew->u.btree.nEq terms of the index pIndex. -** Try to match one more. +** Adjust the cost C by the costMult facter T. This only occurs if +** compiled with -DSQLITE_ENABLE_COSTMULT +*/ +#ifdef SQLITE_ENABLE_COSTMULT +# define ApplyCostMultiplier(C,T) C += T +#else +# define ApplyCostMultiplier(C,T) +#endif + +/* +** We have so far matched pBuilder->pNew->u.btree.nEq terms of the +** index pIndex. Try to match one more. +** +** When this function is called, pBuilder->pNew->nOut contains the +** number of rows expected to be visited by filtering using the nEq +** terms only. If it is modified, this value is restored before this +** function returns. ** ** If pProbe->tnum==0, that means pIndex is a fake index used for the ** INTEGER PRIMARY KEY. @@ -113306,7 +115168,6 @@ static int whereLoopAddBtreeIndex( LogEst saved_nOut; /* Original value of pNew->nOut */ int iCol; /* Index of the column in the table */ int rc = SQLITE_OK; /* Return code */ - LogEst nRowEst; /* Estimated index selectivity */ LogEst rLogSize; /* Logarithm of table size */ WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */ @@ -113324,15 +115185,9 @@ static int whereLoopAddBtreeIndex( } if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); - assert( pNew->u.btree.nEq<=pProbe->nKeyCol ); - if( pNew->u.btree.nEq < pProbe->nKeyCol ){ - iCol = pProbe->aiColumn[pNew->u.btree.nEq]; - nRowEst = sqlite3LogEst(pProbe->aiRowEst[pNew->u.btree.nEq+1]); - if( nRowEst==0 && pProbe->onError==OE_None ) nRowEst = 1; - }else{ - iCol = -1; - nRowEst = 0; - } + assert( pNew->u.btree.nEqnColumn ); + iCol = pProbe->aiColumn[pNew->u.btree.nEq]; + pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol, opMask, pProbe); saved_nEq = pNew->u.btree.nEq; @@ -113342,18 +115197,23 @@ static int whereLoopAddBtreeIndex( saved_prereq = pNew->prereq; saved_nOut = pNew->nOut; pNew->rSetup = 0; - rLogSize = estLog(sqlite3LogEst(pProbe->aiRowEst[0])); + rLogSize = estLog(pProbe->aiRowLogEst[0]); /* Consider using a skip-scan if there are no WHERE clause constraints ** available for the left-most terms of the index, and if the average - ** number of repeats in the left-most terms is at least 18. The magic - ** number 18 was found by experimentation to be the payoff point where - ** skip-scan become faster than a full-scan. - */ + ** number of repeats in the left-most terms is at least 18. + ** + ** The magic number 18 is selected on the basis that scanning 17 rows + ** is almost always quicker than an index seek (even though if the index + ** contains fewer than 2^17 rows we assume otherwise in other parts of + ** the code). And, even if it is not, it should not be too much slower. + ** On the other hand, the extra seeks could end up being significantly + ** more expensive. */ + assert( 42==sqlite3LogEst(18) ); if( pTerm==0 && saved_nEq==saved_nSkip && saved_nEq+1nKeyCol - && pProbe->aiRowEst[saved_nEq+1]>=18 /* TUNING: Minimum for skip-scan */ + && pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */ && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK ){ LogEst nIter; @@ -113361,34 +115221,40 @@ static int whereLoopAddBtreeIndex( pNew->u.btree.nSkip++; pNew->aLTerm[pNew->nLTerm++] = 0; pNew->wsFlags |= WHERE_SKIPSCAN; - nIter = sqlite3LogEst(pProbe->aiRowEst[0]/pProbe->aiRowEst[saved_nEq+1]); - pNew->rRun = rLogSize + nIter; - pNew->nOut += nIter; - whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter); + nIter = pProbe->aiRowLogEst[saved_nEq] - pProbe->aiRowLogEst[saved_nEq+1]; + pNew->nOut -= nIter; + whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter + nInMul); pNew->nOut = saved_nOut; } for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){ + u16 eOp = pTerm->eOperator; /* Shorthand for pTerm->eOperator */ + LogEst rCostIdx; + LogEst nOutUnadjusted; /* nOut before IN() and WHERE adjustments */ int nIn = 0; #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 int nRecValid = pBuilder->nRecValid; #endif - if( (pTerm->eOperator==WO_ISNULL || (pTerm->wtFlags&TERM_VNULL)!=0) + if( (eOp==WO_ISNULL || (pTerm->wtFlags&TERM_VNULL)!=0) && (iCol<0 || pSrc->pTab->aCol[iCol].notNull) ){ continue; /* ignore IS [NOT] NULL constraints on NOT NULL columns */ } if( pTerm->prereqRight & pNew->maskSelf ) continue; - assert( pNew->nOut==saved_nOut ); - pNew->wsFlags = saved_wsFlags; pNew->u.btree.nEq = saved_nEq; pNew->nLTerm = saved_nLTerm; if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */ pNew->aLTerm[pNew->nLTerm++] = pTerm; pNew->prereq = (saved_prereq | pTerm->prereqRight) & ~pNew->maskSelf; - pNew->rRun = rLogSize; /* Baseline cost is log2(N). Adjustments below */ - if( pTerm->eOperator & WO_IN ){ + + assert( nInMul==0 + || (pNew->wsFlags & WHERE_COLUMN_NULL)!=0 + || (pNew->wsFlags & WHERE_COLUMN_IN)!=0 + || (pNew->wsFlags & WHERE_SKIPSCAN)!=0 + ); + + if( eOp & WO_IN ){ Expr *pExpr = pTerm->pExpr; pNew->wsFlags |= WHERE_COLUMN_IN; if( ExprHasProperty(pExpr, EP_xIsSelect) ){ @@ -113398,85 +115264,120 @@ static int whereLoopAddBtreeIndex( /* "x IN (value, value, ...)" */ nIn = sqlite3LogEst(pExpr->x.pList->nExpr); } - pNew->rRun += nIn; - pNew->u.btree.nEq++; - pNew->nOut = nRowEst + nInMul + nIn; - }else if( pTerm->eOperator & (WO_EQ) ){ - assert( - (pNew->wsFlags & (WHERE_COLUMN_NULL|WHERE_COLUMN_IN|WHERE_SKIPSCAN))!=0 - || nInMul==0 - ); + assert( nIn>0 ); /* RHS always has 2 or more terms... The parser + ** changes "x IN (?)" into "x=?". */ + + }else if( eOp & (WO_EQ) ){ pNew->wsFlags |= WHERE_COLUMN_EQ; - if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1)){ - assert( (pNew->wsFlags & WHERE_COLUMN_IN)==0 || iCol<0 ); - if( iCol>=0 && pProbe->onError==OE_None ){ + if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1) ){ + if( iCol>=0 && !IsUniqueIndex(pProbe) ){ pNew->wsFlags |= WHERE_UNQ_WANTED; }else{ pNew->wsFlags |= WHERE_ONEROW; } } - pNew->u.btree.nEq++; - pNew->nOut = nRowEst + nInMul; - }else if( pTerm->eOperator & (WO_ISNULL) ){ + }else if( eOp & WO_ISNULL ){ pNew->wsFlags |= WHERE_COLUMN_NULL; - pNew->u.btree.nEq++; - /* TUNING: IS NULL selects 2 rows */ - nIn = 10; assert( 10==sqlite3LogEst(2) ); - pNew->nOut = nRowEst + nInMul + nIn; - }else if( pTerm->eOperator & (WO_GT|WO_GE) ){ - testcase( pTerm->eOperator & WO_GT ); - testcase( pTerm->eOperator & WO_GE ); + }else if( eOp & (WO_GT|WO_GE) ){ + testcase( eOp & WO_GT ); + testcase( eOp & WO_GE ); pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; pBtm = pTerm; pTop = 0; }else{ - assert( pTerm->eOperator & (WO_LT|WO_LE) ); - testcase( pTerm->eOperator & WO_LT ); - testcase( pTerm->eOperator & WO_LE ); + assert( eOp & (WO_LT|WO_LE) ); + testcase( eOp & WO_LT ); + testcase( eOp & WO_LE ); pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT; pTop = pTerm; pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ? pNew->aLTerm[pNew->nLTerm-2] : 0; } + + /* At this point pNew->nOut is set to the number of rows expected to + ** be visited by the index scan before considering term pTerm, or the + ** values of nIn and nInMul. In other words, assuming that all + ** "x IN(...)" terms are replaced with "x = ?". This block updates + ** the value of pNew->nOut to account for pTerm (but not nIn/nInMul). */ + assert( pNew->nOut==saved_nOut ); if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ - /* Adjust nOut and rRun for STAT3 range values */ - assert( pNew->nOut==saved_nOut ); + /* Adjust nOut using stat3/stat4 data. Or, if there is no stat3/stat4 + ** data, using some other estimate. */ whereRangeScanEst(pParse, pBuilder, pBtm, pTop, pNew); - } + }else{ + int nEq = ++pNew->u.btree.nEq; + assert( eOp & (WO_ISNULL|WO_EQ|WO_IN) ); + + assert( pNew->nOut==saved_nOut ); + if( pTerm->truthProb<=0 && iCol>=0 ){ + assert( (eOp & WO_IN) || nIn==0 ); + testcase( eOp & WO_IN ); + pNew->nOut += pTerm->truthProb; + pNew->nOut -= nIn; + }else{ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - if( nInMul==0 - && pProbe->nSample - && pNew->u.btree.nEq<=pProbe->nSampleCol - && OptimizationEnabled(db, SQLITE_Stat3) - ){ - Expr *pExpr = pTerm->pExpr; - tRowcnt nOut = 0; - if( (pTerm->eOperator & (WO_EQ|WO_ISNULL))!=0 ){ - testcase( pTerm->eOperator & WO_EQ ); - testcase( pTerm->eOperator & WO_ISNULL ); - rc = whereEqualScanEst(pParse, pBuilder, pExpr->pRight, &nOut); - }else if( (pTerm->eOperator & WO_IN) - && !ExprHasProperty(pExpr, EP_xIsSelect) ){ - rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut); - } - assert( nOut==0 || rc==SQLITE_OK ); - if( nOut ){ - pNew->nOut = sqlite3LogEst(nOut); - if( pNew->nOut>saved_nOut ) pNew->nOut = saved_nOut; - } - } + tRowcnt nOut = 0; + if( nInMul==0 + && pProbe->nSample + && pNew->u.btree.nEq<=pProbe->nSampleCol + && OptimizationEnabled(db, SQLITE_Stat3) + && ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect)) + ){ + Expr *pExpr = pTerm->pExpr; + if( (eOp & (WO_EQ|WO_ISNULL))!=0 ){ + testcase( eOp & WO_EQ ); + testcase( eOp & WO_ISNULL ); + rc = whereEqualScanEst(pParse, pBuilder, pExpr->pRight, &nOut); + }else{ + rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut); + } + if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; + if( rc!=SQLITE_OK ) break; /* Jump out of the pTerm loop */ + if( nOut ){ + pNew->nOut = sqlite3LogEst(nOut); + if( pNew->nOut>saved_nOut ) pNew->nOut = saved_nOut; + pNew->nOut -= nIn; + } + } + if( nOut==0 ) #endif - if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){ - /* Each row involves a step of the index, then a binary search of - ** the main table */ - pNew->rRun = sqlite3LogEstAdd(pNew->rRun,rLogSize>27 ? rLogSize-17 : 10); + { + pNew->nOut += (pProbe->aiRowLogEst[nEq] - pProbe->aiRowLogEst[nEq-1]); + if( eOp & WO_ISNULL ){ + /* TUNING: If there is no likelihood() value, assume that a + ** "col IS NULL" expression matches twice as many rows + ** as (col=?). */ + pNew->nOut += 10; + } + } + } } - /* Step cost for each output row */ - pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut); + + /* Set rCostIdx to the cost of visiting selected rows in index. Add + ** it to pNew->rRun, which is currently set to the cost of the index + ** seek only. Then, if this is a non-covering index, add the cost of + ** visiting the rows in the main table. */ + rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow; + pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx); + if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){ + pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut + 16); + } + ApplyCostMultiplier(pNew->rRun, pProbe->pTable->costMult); + + nOutUnadjusted = pNew->nOut; + pNew->rRun += nInMul + nIn; + pNew->nOut += nInMul + nIn; whereLoopOutputAdjust(pBuilder->pWC, pNew); rc = whereLoopInsert(pBuilder, pNew); + + if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ + pNew->nOut = saved_nOut; + }else{ + pNew->nOut = nOutUnadjusted; + } + if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 - && pNew->u.btree.nEq<(pProbe->nKeyCol + (pProbe->zName!=0)) + && pNew->u.btree.nEqnColumn ){ whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul+nIn); } @@ -113558,6 +115459,37 @@ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){ ** Add all WhereLoop objects for a single table of the join where the table ** is idenfied by pBuilder->pNew->iTab. That table is guaranteed to be ** a b-tree table, not a virtual table. +** +** The costs (WhereLoop.rRun) of the b-tree loops added by this function +** are calculated as follows: +** +** For a full scan, assuming the table (or index) contains nRow rows: +** +** cost = nRow * 3.0 // full-table scan +** cost = nRow * K // scan of covering index +** cost = nRow * (K+3.0) // scan of non-covering index +** +** where K is a value between 1.1 and 3.0 set based on the relative +** estimated average size of the index and table records. +** +** For an index scan, where nVisit is the number of index rows visited +** by the scan, and nSeek is the number of seek operations required on +** the index b-tree: +** +** cost = nSeek * (log(nRow) + K * nVisit) // covering index +** cost = nSeek * (log(nRow) + (K+3.0) * nVisit) // non-covering index +** +** Normally, nSeek is 1. nSeek values greater than 1 come about if the +** WHERE clause includes "x IN (....)" terms used in place of "x=?". Or when +** implicit "x IN (SELECT x FROM tbl)" terms are added for skip-scans. +** +** The estimated values (nRow, nVisit, nSeek) often contain a large amount +** of uncertainty. For this reason, scoring is designed to pick plans that +** "do the least harm" if the estimates are inaccurate. For example, a +** log(nRow) factor is omitted from a non-covering index scan in order to +** bias the scoring in favor of using an index, since the worst-case +** performance of using an index is far better than the worst-case performance +** of a full table scan. */ static int whereLoopAddBtree( WhereLoopBuilder *pBuilder, /* WHERE clause information */ @@ -113566,7 +115498,7 @@ static int whereLoopAddBtree( WhereInfo *pWInfo; /* WHERE analysis context */ Index *pProbe; /* An index we are evaluating */ Index sPk; /* A fake index object for the primary key */ - tRowcnt aiRowEstPk[2]; /* The aiRowEst[] value for the sPk index */ + LogEst aiRowEstPk[2]; /* The aiRowLogEst[] value for the sPk index */ i16 aiColumnPk = -1; /* The aColumn[] value for the sPk index */ SrcList *pTabList; /* The FROM clause */ struct SrcList_item *pSrc; /* The FROM clause btree term to add */ @@ -113600,12 +115532,14 @@ static int whereLoopAddBtree( Index *pFirst; /* First of real indices on the table */ memset(&sPk, 0, sizeof(Index)); sPk.nKeyCol = 1; + sPk.nColumn = 1; sPk.aiColumn = &aiColumnPk; - sPk.aiRowEst = aiRowEstPk; + sPk.aiRowLogEst = aiRowEstPk; sPk.onError = OE_Replace; sPk.pTable = pTab; - aiRowEstPk[0] = pTab->nRowEst; - aiRowEstPk[1] = 1; + sPk.szIdxRow = pTab->szTabRow; + aiRowEstPk[0] = pTab->nRowLogEst; + aiRowEstPk[1] = 0; pFirst = pSrc->pTab->pIndex; if( pSrc->notIndexed==0 ){ /* The real indices of the table are only considered if the @@ -113614,7 +115548,7 @@ static int whereLoopAddBtree( } pProbe = &sPk; } - rSize = sqlite3LogEst(pTab->nRowEst); + rSize = pTab->nRowLogEst; rLogSize = estLog(rSize); #ifndef SQLITE_OMIT_AUTOMATIC_INDEX @@ -113643,6 +115577,7 @@ static int whereLoopAddBtree( ** approximately 7*N*log2(N) where N is the number of rows in ** the table being indexed. */ pNew->rSetup = rLogSize + rSize + 28; assert( 28==sqlite3LogEst(7) ); + ApplyCostMultiplier(pNew->rSetup, pTab->costMult); /* TUNING: Each index lookup yields 20 rows in the table. This ** is more than the usual guess of 10 rows, since we have no way ** of knowning how selective the index will ultimately be. It would @@ -113664,6 +115599,7 @@ static int whereLoopAddBtree( && !whereUsablePartialIndex(pNew->iTab, pWC, pProbe->pPartIdxWhere) ){ continue; /* Partial index inappropriate for this query */ } + rSize = pProbe->aiRowLogEst[0]; pNew->u.btree.nEq = 0; pNew->u.btree.nSkip = 0; pNew->nLTerm = 0; @@ -113681,10 +115617,9 @@ static int whereLoopAddBtree( /* Full table scan */ pNew->iSortIdx = b ? iSortIdx : 0; - /* TUNING: Cost of full table scan is 3*(N + log2(N)). - ** + The extra 3 factor is to encourage the use of indexed lookups - ** over full scans. FIXME */ - pNew->rRun = sqlite3LogEstAdd(rSize,rLogSize) + 16; + /* TUNING: Cost of full table scan is (N*3.0). */ + pNew->rRun = rSize + 16; + ApplyCostMultiplier(pNew->rRun, pTab->costMult); whereLoopOutputAdjust(pWC, pNew); rc = whereLoopInsert(pBuilder, pNew); pNew->nOut = rSize; @@ -113711,19 +115646,16 @@ static int whereLoopAddBtree( ) ){ pNew->iSortIdx = b ? iSortIdx : 0; - if( m==0 ){ - /* TUNING: Cost of a covering index scan is K*(N + log2(N)). - ** + The extra factor K of between 1.1 and 3.0 that depends - ** on the relative sizes of the table and the index. K - ** is smaller for smaller indices, thus favoring them. - */ - pNew->rRun = sqlite3LogEstAdd(rSize,rLogSize) + 1 + - (15*pProbe->szIdxRow)/pTab->szTabRow; - }else{ - /* TUNING: Cost of scanning a non-covering index is (N+1)*log2(N) - ** which we will simplify to just N*log2(N) */ - pNew->rRun = rSize + rLogSize; + + /* The cost of visiting the index rows is N*K, where K is + ** between 1.1 and 3.0, depending on the relative sizes of the + ** index and table rows. If this is a non-covering index scan, + ** also add the cost of visiting table rows (N*3.0). */ + pNew->rRun = rSize + 1 + (15*pProbe->szIdxRow)/pTab->szTabRow; + if( m!=0 ){ + pNew->rRun = sqlite3LogEstAdd(pNew->rRun, rSize+16); } + ApplyCostMultiplier(pNew->rRun, pTab->costMult); whereLoopOutputAdjust(pWC, pNew); rc = whereLoopInsert(pBuilder, pNew); pNew->nOut = rSize; @@ -113894,8 +115826,8 @@ static int whereLoopAddVirtual( pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr; pIdxInfo->needToFreeIdxStr = 0; pNew->u.vtab.idxStr = pIdxInfo->idxStr; - pNew->u.vtab.isOrdered = (u8)((pIdxInfo->nOrderBy!=0) - && pIdxInfo->orderByConsumed); + pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ? + pIdxInfo->nOrderBy : 0); pNew->rSetup = 0; pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost); pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows); @@ -113927,7 +115859,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ int iCur; WhereClause tempWC; WhereLoopBuilder sSubBuild; - WhereOrSet sSum, sCur, sPrev; + WhereOrSet sSum, sCur; struct SrcList_item *pItem; pWC = pBuilder->pWC; @@ -113936,7 +115868,6 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ pNew = pBuilder->pNew; memset(&sSum, 0, sizeof(sSum)); pItem = pWInfo->pTabList->a + pNew->iTab; - if( !HasRowid(pItem->pTab) ) return SQLITE_OK; iCur = pItem->iCursor; for(pTerm=pWC->a; pTermiSortIdx = 0; memset(&pNew->u, 0, sizeof(pNew->u)); for(i=0; rc==SQLITE_OK && irRun = sSum.a[i].rRun + 18; + /* TUNING: Currently sSum.a[i].rRun is set to the sum of the costs + ** of all sub-scans required by the OR-scan. However, due to rounding + ** errors, it may be that the cost of the OR-scan is equal to its + ** most expensive sub-scan. Add the smallest possible penalty + ** (equivalent to multiplying the cost by 1.07) to ensure that + ** this does not happen. Otherwise, for WHERE clauses such as the + ** following where there is an index on "y": + ** + ** WHERE likelihood(x=?, 0.99) OR y=? + ** + ** the planner may elect to "OR" together a full-table scan and an + ** index lookup. And other similarly odd results. */ + pNew->rRun = sSum.a[i].rRun + 1; pNew->nOut = sSum.a[i].nOut; pNew->prereq = sSum.a[i].prereq; rc = whereLoopInsert(pBuilder, pNew); @@ -114056,21 +115999,21 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ /* ** Examine a WherePath (with the addition of the extra WhereLoop of the 5th ** parameters) to see if it outputs rows in the requested ORDER BY -** (or GROUP BY) without requiring a separate sort operation. Return: +** (or GROUP BY) without requiring a separate sort operation. Return N: ** -** 0: ORDER BY is not satisfied. Sorting required -** 1: ORDER BY is satisfied. Omit sorting -** -1: Unknown at this time +** N>0: N terms of the ORDER BY clause are satisfied +** N==0: No terms of the ORDER BY clause are satisfied +** N<0: Unknown yet how many terms of ORDER BY might be satisfied. ** ** Note that processing for WHERE_GROUPBY and WHERE_DISTINCTBY is not as ** strict. With GROUP BY and DISTINCT the only requirement is that ** equivalent rows appear immediately adjacent to one another. GROUP BY -** and DISTINT do not require rows to appear in any particular order as long +** and DISTINCT do not require rows to appear in any particular order as long ** as equivelent rows are grouped together. Thus for GROUP BY and DISTINCT ** the pOrderBy terms can be matched in any order. With ORDER BY, the ** pOrderBy terms must be matched in strict left-to-right order. */ -static int wherePathSatisfiesOrderBy( +static i8 wherePathSatisfiesOrderBy( WhereInfo *pWInfo, /* The WHERE clause */ ExprList *pOrderBy, /* ORDER BY or GROUP BY or DISTINCT clause to check */ WherePath *pPath, /* The WherePath to check */ @@ -114126,14 +116069,6 @@ static int wherePathSatisfiesOrderBy( */ assert( pOrderBy!=0 ); - - /* Sortability of virtual tables is determined by the xBestIndex method - ** of the virtual table itself */ - if( pLast->wsFlags & WHERE_VIRTUALTABLE ){ - testcase( nLoop>0 ); /* True when outer loops are one-row and match - ** no ORDER BY terms */ - return pLast->u.vtab.isOrdered; - } if( nLoop && OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ) return 0; nOrderBy = pOrderBy->nExpr; @@ -114146,7 +116081,10 @@ static int wherePathSatisfiesOrderBy( for(iLoop=0; isOrderDistinct && obSat0 ) ready |= pLoop->maskSelf; pLoop = iLoopaLoop[iLoop] : pLast; - assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ); + if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){ + if( pLoop->u.vtab.isOrdered ) obSat = obDone; + break; + } iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor; /* Mark off any ORDER BY term X that is a column in the table of @@ -114187,7 +116125,7 @@ static int wherePathSatisfiesOrderBy( nColumn = pIndex->nColumn; assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) ); assert( pIndex->aiColumn[nColumn-1]==(-1) || !HasRowid(pIndex->pTable)); - isOrderDistinct = pIndex->onError!=OE_None; + isOrderDistinct = IsUniqueIndex(pIndex); } /* Loop through all columns of the index and deal with the ones @@ -114234,7 +116172,7 @@ static int wherePathSatisfiesOrderBy( } /* Find the ORDER BY term that corresponds to the j-th column - ** of the index and and mark that ORDER BY term off + ** of the index and mark that ORDER BY term off */ bOnce = 1; isMatch = 0; @@ -114255,23 +116193,23 @@ static int wherePathSatisfiesOrderBy( isMatch = 1; break; } + if( isMatch && (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){ + /* Make sure the sort order is compatible in an ORDER BY clause. + ** Sort order is irrelevant for a GROUP BY clause. */ + if( revSet ){ + if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) isMatch = 0; + }else{ + rev = revIdx ^ pOrderBy->a[i].sortOrder; + if( rev ) *pRevMask |= MASKBIT(iLoop); + revSet = 1; + } + } if( isMatch ){ if( iColumn<0 ){ testcase( distinctColumns==0 ); distinctColumns = 1; } obSat |= MASKBIT(i); - if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){ - /* Make sure the sort order is compatible in an ORDER BY clause. - ** Sort order is irrelevant for a GROUP BY clause. */ - if( revSet ){ - if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) return 0; - }else{ - rev = revIdx ^ pOrderBy->a[i].sortOrder; - if( rev ) *pRevMask |= MASKBIT(iLoop); - revSet = 1; - } - } }else{ /* No match found */ if( j==0 || j0; i--){ + Bitmask m = MASKBIT(i) - 1; + if( (obSat&m)==m ) return i; + } + return 0; + } return -1; } + +/* +** If the WHERE_GROUPBY flag is set in the mask passed to sqlite3WhereBegin(), +** the planner assumes that the specified pOrderBy list is actually a GROUP +** BY clause - and so any order that groups rows as required satisfies the +** request. +** +** Normally, in this case it is not possible for the caller to determine +** whether or not the rows are really being delivered in sorted order, or +** just in some other order that provides the required grouping. However, +** if the WHERE_SORTBYGROUP flag is also passed to sqlite3WhereBegin(), then +** this function may be called on the returned WhereInfo object. It returns +** true if the rows really will be sorted in the specified order, or false +** otherwise. +** +** For example, assuming: +** +** CREATE INDEX i1 ON t1(x, Y); +** +** then +** +** SELECT * FROM t1 GROUP BY x,y ORDER BY x,y; -- IsSorted()==1 +** SELECT * FROM t1 GROUP BY y,x ORDER BY y,x; -- IsSorted()==0 +*/ +SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo *pWInfo){ + assert( pWInfo->wctrlFlags & WHERE_GROUPBY ); + assert( pWInfo->wctrlFlags & WHERE_SORTBYGROUP ); + return pWInfo->sorted; +} + #ifdef WHERETRACE_ENABLED /* For debugging use only: */ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){ @@ -114320,6 +116294,44 @@ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){ } #endif +/* +** Return the cost of sorting nRow rows, assuming that the keys have +** nOrderby columns and that the first nSorted columns are already in +** order. +*/ +static LogEst whereSortingCost( + WhereInfo *pWInfo, + LogEst nRow, + int nOrderBy, + int nSorted +){ + /* TUNING: Estimated cost of a full external sort, where N is + ** the number of rows to sort is: + ** + ** cost = (3.0 * N * log(N)). + ** + ** Or, if the order-by clause has X terms but only the last Y + ** terms are out of order, then block-sorting will reduce the + ** sorting cost to: + ** + ** cost = (3.0 * N * log(N)) * (Y/X) + ** + ** The (Y/X) term is implemented using stack variable rScale + ** below. */ + LogEst rScale, rSortCost; + assert( nOrderBy>0 && 66==sqlite3LogEst(100) ); + rScale = sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66; + rSortCost = nRow + estLog(nRow) + rScale + 16; + + /* TUNING: The cost of implementing DISTINCT using a B-TREE is + ** similar but with a larger constant of proportionality. + ** Multiply by an additional factor of 3.0. */ + if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){ + rSortCost += 16; + } + + return rSortCost; +} /* ** Given the list of WhereLoop objects at pWInfo->pLoops, this routine @@ -114341,11 +116353,9 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ int iLoop; /* Loop counter over the terms of the join */ int ii, jj; /* Loop counters */ int mxI = 0; /* Index of next entry to replace */ - LogEst rCost; /* Cost of a path */ - LogEst nOut; /* Number of outputs */ + int nOrderBy; /* Number of ORDER BY clause terms */ LogEst mxCost = 0; /* Maximum cost of a set of paths */ - LogEst mxOut = 0; /* Maximum nOut value on the set of paths */ - LogEst rSortCost; /* Cost to do a sort */ + LogEst mxUnsorted = 0; /* Maximum unsorted cost of a set of path */ int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */ WherePath *aFrom; /* All nFrom paths at the previous level */ WherePath *aTo; /* The nTo best paths at the current level */ @@ -114353,7 +116363,9 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ WherePath *pTo; /* An element of aTo[] that we are working on */ WhereLoop *pWLoop; /* One of the WhereLoop objects */ WhereLoop **pX; /* Used to divy up the pSpace memory */ + LogEst *aSortCost = 0; /* Sorting and partial sorting costs */ char *pSpace; /* Temporary memory used by this routine */ + int nSpace; /* Bytes of space allocated at pSpace */ pParse = pWInfo->pParse; db = pParse->db; @@ -114361,13 +116373,25 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ /* TUNING: For simple queries, only the best path is tracked. ** For 2-way joins, the 5 best paths are followed. ** For joins of 3 or more tables, track the 10 best paths */ - mxChoice = (nLoop==1) ? 1 : (nLoop==2 ? 5 : 10); + mxChoice = (nLoop<=1) ? 1 : (nLoop==2 ? 5 : 10); assert( nLoop<=pWInfo->pTabList->nSrc ); - WHERETRACE(0x002, ("---- begin solver\n")); + WHERETRACE(0x002, ("---- begin solver. (nRowEst=%d)\n", nRowEst)); - /* Allocate and initialize space for aTo and aFrom */ - ii = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2; - pSpace = sqlite3DbMallocRaw(db, ii); + /* If nRowEst is zero and there is an ORDER BY clause, ignore it. In this + ** case the purpose of this call is to estimate the number of rows returned + ** by the overall query. Once this estimate has been obtained, the caller + ** will invoke this function a second time, passing the estimate as the + ** nRowEst parameter. */ + if( pWInfo->pOrderBy==0 || nRowEst==0 ){ + nOrderBy = 0; + }else{ + nOrderBy = pWInfo->pOrderBy->nExpr; + } + + /* Allocate and initialize space for aTo, aFrom and aSortCost[] */ + nSpace = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2; + nSpace += sizeof(LogEst) * nOrderBy; + pSpace = sqlite3DbMallocRaw(db, nSpace); if( pSpace==0 ) return SQLITE_NOMEM; aTo = (WherePath*)pSpace; aFrom = aTo+mxChoice; @@ -114376,6 +116400,18 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ for(ii=mxChoice*2, pFrom=aTo; ii>0; ii--, pFrom++, pX += nLoop){ pFrom->aLoop = pX; } + if( nOrderBy ){ + /* If there is an ORDER BY clause and it is not being ignored, set up + ** space for the aSortCost[] array. Each element of the aSortCost array + ** is either zero - meaning it has not yet been initialized - or the + ** cost of sorting nRowEst rows of data where the first X terms of + ** the ORDER BY clause are already in order, where X is the array + ** index. */ + aSortCost = (LogEst*)pX; + memset(aSortCost, 0, sizeof(LogEst) * nOrderBy); + } + assert( aSortCost==0 || &pSpace[nSpace]==(char*)&aSortCost[nOrderBy] ); + assert( aSortCost!=0 || &pSpace[nSpace]==(char*)pX ); /* Seed the search with a single WherePath containing zero WhereLoops. ** @@ -114384,19 +116420,15 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ ** rows, then do not use the automatic index. */ aFrom[0].nRow = MIN(pParse->nQueryLoop, 46); assert( 46==sqlite3LogEst(25) ); nFrom = 1; - - /* Precompute the cost of sorting the final result set, if the caller - ** to sqlite3WhereBegin() was concerned about sorting */ - rSortCost = 0; - if( pWInfo->pOrderBy==0 || nRowEst==0 ){ - aFrom[0].isOrderedValid = 1; - }else{ - /* TUNING: Estimated cost of sorting is 48*N*log2(N) where N is the - ** number of output rows. The 48 is the expected size of a row to sort. - ** FIXME: compute a better estimate of the 48 multiplier based on the - ** result set expressions. */ - rSortCost = nRowEst + estLog(nRowEst); - WHERETRACE(0x002,("---- sort cost=%-3d\n", rSortCost)); + assert( aFrom[0].isOrdered==0 ); + if( nOrderBy ){ + /* If nLoop is zero, then there are no FROM terms in the query. Since + ** in this case the query may return a maximum of one row, the results + ** are already in the requested order. Set isOrdered to nOrderBy to + ** indicate this. Or, if nLoop is greater than zero, set isOrdered to + ** -1, indicating that the result set may or may not be ordered, + ** depending on the loops added to the current plan. */ + aFrom[0].isOrdered = nLoop>0 ? -1 : nOrderBy; } /* Compute successively longer WherePaths using the previous generation @@ -114406,60 +116438,82 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ nTo = 0; for(ii=0, pFrom=aFrom; iipLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ - Bitmask maskNew; - Bitmask revMask = 0; - u8 isOrderedValid = pFrom->isOrderedValid; - u8 isOrdered = pFrom->isOrdered; + LogEst nOut; /* Rows visited by (pFrom+pWLoop) */ + LogEst rCost; /* Cost of path (pFrom+pWLoop) */ + LogEst rUnsorted; /* Unsorted cost of (pFrom+pWLoop) */ + i8 isOrdered = pFrom->isOrdered; /* isOrdered for (pFrom+pWLoop) */ + Bitmask maskNew; /* Mask of src visited by (..) */ + Bitmask revMask = 0; /* Mask of rev-order loops for (..) */ + if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue; if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue; /* At this point, pWLoop is a candidate to be the next loop. ** Compute its cost */ - rCost = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow); - rCost = sqlite3LogEstAdd(rCost, pFrom->rCost); + rUnsorted = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow); + rUnsorted = sqlite3LogEstAdd(rUnsorted, pFrom->rUnsorted); nOut = pFrom->nRow + pWLoop->nOut; maskNew = pFrom->maskLoop | pWLoop->maskSelf; - if( !isOrderedValid ){ - switch( wherePathSatisfiesOrderBy(pWInfo, + if( isOrdered<0 ){ + isOrdered = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags, - iLoop, pWLoop, &revMask) ){ - case 1: /* Yes. pFrom+pWLoop does satisfy the ORDER BY clause */ - isOrdered = 1; - isOrderedValid = 1; - break; - case 0: /* No. pFrom+pWLoop will require a separate sort */ - isOrdered = 0; - isOrderedValid = 1; - rCost = sqlite3LogEstAdd(rCost, rSortCost); - break; - default: /* Cannot tell yet. Try again on the next iteration */ - break; - } + iLoop, pWLoop, &revMask); }else{ revMask = pFrom->revLoop; } - /* Check to see if pWLoop should be added to the mxChoice best so far */ + if( isOrdered>=0 && isOrderedisOrdered^isOrdered)&0x80)==0" is equivalent + ** to (pTo->isOrdered==(-1))==(isOrdered==(-1))" for the range + ** of legal values for isOrdered, -1..64. + */ for(jj=0, pTo=aTo; jjmaskLoop==maskNew - && pTo->isOrderedValid==isOrderedValid - && ((pTo->rCost<=rCost && pTo->nRow<=nOut) || - (pTo->rCost>=rCost && pTo->nRow>=nOut)) + && ((pTo->isOrdered^isOrdered)&0x80)==0 ){ testcase( jj==nTo-1 ); break; } } if( jj>=nTo ){ - if( nTo>=mxChoice && rCost>=mxCost ){ + /* None of the existing best-so-far paths match the candidate. */ + if( nTo>=mxChoice + && (rCost>mxCost || (rCost==mxCost && rUnsorted>=mxUnsorted)) + ){ + /* The current candidate is no better than any of the mxChoice + ** paths currently in the best-so-far buffer. So discard + ** this candidate as not viable. */ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf("Skip %s cost=%-3d,%3d order=%c\n", wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, - isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); + isOrdered>=0 ? isOrdered+'0' : '?'); } #endif continue; } - /* Add a new Path to the aTo[] set */ + /* If we reach this points it means that the new candidate path + ** needs to be added to the set of best-so-far paths. */ if( nTo=0 ? isOrdered+'0' : '?'); } #endif }else{ - if( pTo->rCost<=rCost && pTo->nRow<=nOut ){ + /* Control reaches here if best-so-far path pTo=aTo[jj] covers the + ** same set of loops and has the sam isOrdered setting as the + ** candidate path. Check to see if the candidate should replace + ** pTo or if the candidate should be skipped */ + if( pTo->rCostrCost==rCost && pTo->nRow<=nOut) ){ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( "Skip %s cost=%-3d,%3d order=%c", wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, - isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); + isOrdered>=0 ? isOrdered+'0' : '?'); sqlite3DebugPrintf(" vs %s cost=%-3d,%d order=%c\n", wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, - pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?'); + pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); } #endif + /* Discard the candidate path from further consideration */ testcase( pTo->rCost==rCost ); continue; } testcase( pTo->rCost==rCost+1 ); - /* A new and better score for a previously created equivalent path */ + /* Control reaches here if the candidate path is better than the + ** pTo path. Replace pTo with the candidate. */ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( "Update %s cost=%-3d,%3d order=%c", wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, - isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?'); + isOrdered>=0 ? isOrdered+'0' : '?'); sqlite3DebugPrintf(" was %s cost=%-3d,%3d order=%c\n", wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, - pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?'); + pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); } #endif } @@ -114510,18 +116570,20 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ pTo->revLoop = revMask; pTo->nRow = nOut; pTo->rCost = rCost; - pTo->isOrderedValid = isOrderedValid; + pTo->rUnsorted = rUnsorted; pTo->isOrdered = isOrdered; memcpy(pTo->aLoop, pFrom->aLoop, sizeof(WhereLoop*)*iLoop); pTo->aLoop[iLoop] = pWLoop; if( nTo>=mxChoice ){ mxI = 0; mxCost = aTo[0].rCost; - mxOut = aTo[0].nRow; + mxUnsorted = aTo[0].nRow; for(jj=1, pTo=&aTo[1]; jjrCost>mxCost || (pTo->rCost==mxCost && pTo->nRow>mxOut) ){ + if( pTo->rCost>mxCost + || (pTo->rCost==mxCost && pTo->rUnsorted>mxUnsorted) + ){ mxCost = pTo->rCost; - mxOut = pTo->nRow; + mxUnsorted = pTo->rUnsorted; mxI = jj; } } @@ -114535,8 +116597,8 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ for(ii=0, pTo=aTo; iirCost, pTo->nRow, - pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?'); - if( pTo->isOrderedValid && pTo->isOrdered ){ + pTo->isOrdered>=0 ? (pTo->isOrdered+'0') : '?'); + if( pTo->isOrdered>0 ){ sqlite3DebugPrintf(" rev=0x%llx\n", pTo->revLoop); }else{ sqlite3DebugPrintf("\n"); @@ -114579,16 +116641,33 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ Bitmask notUsed; int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pResultSet, pFrom, WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used); - if( rc==1 ) pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; - } - if( pFrom->isOrdered ){ - if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){ + if( rc==pWInfo->pResultSet->nExpr ){ pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; - }else{ - pWInfo->bOBSat = 1; - pWInfo->revMask = pFrom->revLoop; } } + if( pWInfo->pOrderBy ){ + if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){ + if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){ + pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; + } + }else{ + pWInfo->nOBSat = pFrom->isOrdered; + if( pWInfo->nOBSat<0 ) pWInfo->nOBSat = 0; + pWInfo->revMask = pFrom->revLoop; + } + if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP) + && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr + ){ + Bitmask notUsed = 0; + int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, + pFrom, 0, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used + ); + assert( pWInfo->sorted==0 ); + pWInfo->sorted = (nOrder==pWInfo->pOrderBy->nExpr); + } + } + + pWInfo->nRowOut = pFrom->nRow; /* Free temporary memory and return success */ @@ -114642,7 +116721,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pLoop->aLTermSpace==pLoop->aLTerm ); assert( ArraySize(pLoop->aLTermSpace)==4 ); - if( pIdx->onError==OE_None + if( !IsUniqueIndex(pIdx) || pIdx->pPartIdxWhere!=0 || pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace) ) continue; @@ -114670,7 +116749,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ pLoop->maskSelf = getMask(&pWInfo->sMaskSet, iCur); pWInfo->a[0].iTabCur = iCur; pWInfo->nRowOut = 1; - if( pWInfo->pOrderBy ) pWInfo->bOBSat = 1; + if( pWInfo->pOrderBy ) pWInfo->nOBSat = pWInfo->pOrderBy->nExpr; if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } @@ -114774,7 +116853,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( Parse *pParse, /* The parser context */ SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */ Expr *pWhere, /* The WHERE clause */ - ExprList *pOrderBy, /* An ORDER BY clause, or NULL */ + ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */ ExprList *pResultSet, /* Result set of the query */ u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */ int iIdxCur /* If WHERE_ONETABLE_ONLY is set, index cursor number */ @@ -114796,6 +116875,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( /* Variable initialization */ db = pParse->db; memset(&sWLB, 0, sizeof(sWLB)); + + /* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */ + testcase( pOrderBy && pOrderBy->nExpr==BMS-1 ); + if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0; sWLB.pOrderBy = pOrderBy; /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via @@ -114840,7 +116923,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( pWInfo->pTabList = pTabList; pWInfo->pOrderBy = pOrderBy; pWInfo->pResultSet = pResultSet; - pWInfo->iBreak = sqlite3VdbeMakeLabel(v); + pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(v); pWInfo->wctrlFlags = wctrlFlags; pWInfo->savedNQueryLoop = pParse->nQueryLoop; pMaskSet = &pWInfo->sMaskSet; @@ -114874,7 +116957,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( /* Special case: No FROM clause */ if( nTabList==0 ){ - if( pOrderBy ) pWInfo->bOBSat = 1; + if( pOrderBy ) pWInfo->nOBSat = pOrderBy->nExpr; if( wctrlFlags & WHERE_WANT_DISTINCT ){ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } @@ -114985,8 +117068,8 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( if( sqlite3WhereTrace ){ int ii; sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut); - if( pWInfo->bOBSat ){ - sqlite3DebugPrintf(" ORDERBY=0x%llx", pWInfo->revMask); + if( pWInfo->nOBSat>0 ){ + sqlite3DebugPrintf(" ORDERBY=%d,0x%llx", pWInfo->nOBSat, pWInfo->revMask); } switch( pWInfo->eDistinct ){ case WHERE_DISTINCT_UNIQUE: { @@ -115109,7 +117192,14 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( int op = OP_OpenRead; /* iIdxCur is always set if to a positive value if ONEPASS is possible */ assert( iIdxCur!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 ); - if( pWInfo->okOnePass ){ + if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIx) + && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0 + ){ + /* This is one term of an OR-optimization using the PRIMARY KEY of a + ** WITHOUT ROWID table. No need for a separate index */ + iIndexCur = pLevel->iTabCur; + op = 0; + }else if( pWInfo->okOnePass ){ Index *pJ = pTabItem->pTab->pIndex; iIndexCur = iIdxCur; assert( wctrlFlags & WHERE_ONEPASS_DESIRED ); @@ -115121,15 +117211,18 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( pWInfo->aiCurOnePass[1] = iIndexCur; }else if( iIdxCur && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ){ iIndexCur = iIdxCur; + if( wctrlFlags & WHERE_REOPEN_IDX ) op = OP_ReopenIdx; }else{ iIndexCur = pParse->nTab++; } pLevel->iIdxCur = iIndexCur; assert( pIx->pSchema==pTab->pSchema ); assert( iIndexCur>=0 ); - sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb); - sqlite3VdbeSetP4KeyInfo(pParse, pIx); - VdbeComment((v, "%s", pIx->zName)); + if( op ){ + sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb); + sqlite3VdbeSetP4KeyInfo(pParse, pIx); + VdbeComment((v, "%s", pIx->zName)); + } } if( iDb>=0 ) sqlite3CodeVerifySchema(pParse, iDb); notReady &= ~getMask(&pWInfo->sMaskSet, pTabItem->iCursor); @@ -115268,7 +117361,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ for(; kp1!=pLevel->iTabCur ) continue; if( pOp->opcode==OP_Column ){ - pOp->opcode = OP_SCopy; + pOp->opcode = OP_Copy; pOp->p1 = pOp->p2 + pTabItem->regResult; pOp->p2 = pOp->p3; pOp->p3 = 0; @@ -118216,6 +120309,33 @@ static void yy_reduce( */ yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[yymsp[-3].minor.yy328]); sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy346.pExpr); + }else if( yymsp[-1].minor.yy14->nExpr==1 ){ + /* Expressions of the form: + ** + ** expr1 IN (?1) + ** expr1 NOT IN (?2) + ** + ** with exactly one value on the RHS can be simplified to something + ** like this: + ** + ** expr1 == ?1 + ** expr1 <> ?2 + ** + ** But, the RHS of the == or <> is marked with the EP_Generic flag + ** so that it may not contribute to the computation of comparison + ** affinity or the collating sequence to use for comparison. Otherwise, + ** the semantics would be subtly different from IN or NOT IN. + */ + Expr *pRHS = yymsp[-1].minor.yy14->a[0].pExpr; + yymsp[-1].minor.yy14->a[0].pExpr = 0; + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14); + /* pRHS cannot be NULL because a malloc error would have been detected + ** before now and control would have never reached this point */ + if( ALWAYS(pRHS) ){ + pRHS->flags &= ~EP_Collate; + pRHS->flags |= EP_Generic; + } + yygotominor.yy346.pExpr = sqlite3PExpr(pParse, yymsp[-3].minor.yy328 ? TK_NE : TK_EQ, yymsp[-4].minor.yy346.pExpr, pRHS, 0); }else{ yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy346.pExpr, 0, 0); if( yygotominor.yy346.pExpr ){ @@ -119416,6 +121536,12 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' ); testcase( z[0]=='9' ); *tokenType = TK_INTEGER; +#ifndef SQLITE_OMIT_HEX_INTEGER + if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){ + for(i=3; sqlite3Isxdigit(z[i]); i++){} + return i; + } +#endif for(i=0; sqlite3Isdigit(z[i]); i++){} #ifndef SQLITE_OMIT_FLOATING_POINT if( z[i]=='.' ){ @@ -120836,6 +122962,7 @@ static void disconnectAllVtab(sqlite3 *db){ } } } + sqlite3VtabUnlockList(db); sqlite3BtreeLeaveAll(db); #else UNUSED_PARAMETER(db); @@ -120862,6 +122989,8 @@ static int connectionIsBusy(sqlite3 *db){ */ static int sqlite3Close(sqlite3 *db, int forceZombie){ if( !db ){ + /* EVIDENCE-OF: R-63257-11740 Calling sqlite3_close() or + ** sqlite3_close_v2() with a NULL pointer argument is a harmless no-op. */ return SQLITE_OK; } if( !sqlite3SafetyCheckSickOrOk(db) ){ @@ -121091,7 +123220,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){ ** Return a static string containing the name corresponding to the error code ** specified in the argument. */ -#if defined(SQLITE_TEST) +#if (defined(SQLITE_DEBUG) && SQLITE_OS_WIN) || defined(SQLITE_TEST) SQLITE_PRIVATE const char *sqlite3ErrName(int rc){ const char *zName = 0; int i, origRc = rc; @@ -121126,7 +123255,6 @@ SQLITE_PRIVATE const char *sqlite3ErrName(int rc){ case SQLITE_IOERR_UNLOCK: zName = "SQLITE_IOERR_UNLOCK"; break; case SQLITE_IOERR_RDLOCK: zName = "SQLITE_IOERR_RDLOCK"; break; case SQLITE_IOERR_DELETE: zName = "SQLITE_IOERR_DELETE"; break; - case SQLITE_IOERR_BLOCKED: zName = "SQLITE_IOERR_BLOCKED"; break; case SQLITE_IOERR_NOMEM: zName = "SQLITE_IOERR_NOMEM"; break; case SQLITE_IOERR_ACCESS: zName = "SQLITE_IOERR_ACCESS"; break; case SQLITE_IOERR_CHECKRESERVEDLOCK: @@ -122111,7 +124239,7 @@ static const int aHardLimit[] = { SQLITE_MAX_FUNCTION_ARG, SQLITE_MAX_ATTACHED, SQLITE_MAX_LIKE_PATTERN_LENGTH, - SQLITE_MAX_VARIABLE_NUMBER, + SQLITE_MAX_VARIABLE_NUMBER, /* IMP: R-38091-32352 */ SQLITE_MAX_TRIGGER_DEPTH, }; @@ -122136,8 +124264,8 @@ static const int aHardLimit[] = { #if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>1000 # error SQLITE_MAX_FUNCTION_ARG must be between 0 and 1000 #endif -#if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>62 -# error SQLITE_MAX_ATTACHED must be between 0 and 62 +#if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>125 +# error SQLITE_MAX_ATTACHED must be between 0 and 125 #endif #if SQLITE_MAX_LIKE_PATTERN_LENGTH<1 # error SQLITE_MAX_LIKE_PATTERN_LENGTH must be at least 1 @@ -123149,6 +125277,28 @@ SQLITE_API int sqlite3_test_control(int op, ...){ break; } + /* + ** sqlite3_test_control(FAULT_INSTALL, xCallback) + ** + ** Arrange to invoke xCallback() whenever sqlite3FaultSim() is called, + ** if xCallback is not NULL. + ** + ** As a test of the fault simulator mechanism itself, sqlite3FaultSim(0) + ** is called immediately after installing the new callback and the return + ** value from sqlite3FaultSim(0) becomes the return from + ** sqlite3_test_control(). + */ + case SQLITE_TESTCTRL_FAULT_INSTALL: { + /* MSVC is picky about pulling func ptrs from va lists. + ** http://support.microsoft.com/kb/47961 + ** sqlite3GlobalConfig.xTestCallback = va_arg(ap, int(*)(int)); + */ + typedef int(*TESTCALLBACKFUNC_t)(int); + sqlite3GlobalConfig.xTestCallback = va_arg(ap, TESTCALLBACKFUNC_t); + rc = sqlite3FaultSim(0); + break; + } + /* ** sqlite3_test_control(BENIGN_MALLOC_HOOKS, xBegin, xEnd) ** @@ -123240,6 +125390,22 @@ SQLITE_API int sqlite3_test_control(int op, ...){ break; } + /* + ** sqlite3_test_control(SQLITE_TESTCTRL_BYTEORDER); + ** + ** The integer returned reveals the byte-order of the computer on which + ** SQLite is running: + ** + ** 1 big-endian, determined at run-time + ** 10 little-endian, determined at run-time + ** 432101 big-endian, determined at compile-time + ** 123410 little-endian, determined at compile-time + */ + case SQLITE_TESTCTRL_BYTEORDER: { + rc = SQLITE_BYTEORDER*100 + SQLITE_LITTLEENDIAN*10 + SQLITE_BIGENDIAN; + break; + } + /* sqlite3_test_control(SQLITE_TESTCTRL_RESERVE, sqlite3 *db, int N) ** ** Set the nReserve size to N for the main database on the database @@ -123358,6 +125524,16 @@ SQLITE_API int sqlite3_test_control(int op, ...){ break; } + /* sqlite3_test_control(SQLITE_TESTCTRL_ISINIT); + ** + ** Return SQLITE_OK if SQLite has been initialized and SQLITE_ERROR if + ** not. + */ + case SQLITE_TESTCTRL_ISINIT: { + if( sqlite3GlobalConfig.isInit==0 ) rc = SQLITE_ERROR; + break; + } + } va_end(ap); #endif /* SQLITE_OMIT_BUILTIN_TEST */ @@ -123406,7 +125582,7 @@ SQLITE_API sqlite3_int64 sqlite3_uri_int64( ){ const char *z = sqlite3_uri_parameter(zFilename, zParam); sqlite3_int64 v; - if( z && sqlite3Atoi64(z, &v, sqlite3Strlen30(z), SQLITE_UTF8)==SQLITE_OK ){ + if( z && sqlite3DecOrHexToI64(z, &v)==SQLITE_OK ){ bDflt = v; } return bDflt; @@ -123442,7 +125618,7 @@ SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){ */ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){ Btree *pBt = sqlite3DbNameToBtree(db, zDbName); - return pBt ? sqlite3PagerIsreadonly(sqlite3BtreePager(pBt)) : -1; + return pBt ? sqlite3BtreeIsReadonly(pBt) : -1; } /************** End of main.c ************************************************/ @@ -124562,20 +126738,20 @@ struct Fts3Table { sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */ char *zContentTbl; /* content=xxx option, or NULL */ char *zLanguageid; /* languageid=xxx option, or NULL */ - u8 bAutoincrmerge; /* True if automerge=1 */ + int nAutoincrmerge; /* Value configured by 'automerge' */ u32 nLeafAdd; /* Number of leaf blocks added this trans */ /* Precompiled statements used by the implementation. Each of these ** statements is run and reset within a single virtual table API call. */ - sqlite3_stmt *aStmt[37]; + sqlite3_stmt *aStmt[40]; char *zReadExprlist; char *zWriteExprlist; int nNodeSize; /* Soft limit for node size */ u8 bFts4; /* True for FTS4, false for FTS3 */ - u8 bHasStat; /* True if %_stat table exists */ + u8 bHasStat; /* True if %_stat table exists (2==unknown) */ u8 bHasDocsize; /* True if %_docsize table exists */ u8 bDescIdx; /* True if doclists are in reverse order */ u8 bIgnoreSavepoint; /* True to ignore xSavepoint invocations */ @@ -124937,7 +127113,7 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr); SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *); /* fts3_unicode2.c (functions generated by parsing unicode text files) */ -#ifdef SQLITE_ENABLE_FTS4_UNICODE61 +#ifndef SQLITE_DISABLE_FTS3_UNICODE SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int, int); SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int); SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int); @@ -125990,7 +128166,7 @@ static int fts3InitVtab( p->bHasStat = isFts4; p->bFts4 = isFts4; p->bDescIdx = bDescIdx; - p->bAutoincrmerge = 0xff; /* 0xff means setting unknown */ + p->nAutoincrmerge = 0xff; /* 0xff means setting unknown */ p->zContentTbl = zContent; p->zLanguageid = zLanguageid; zContent = 0; @@ -126033,7 +128209,9 @@ static int fts3InitVtab( int n = (int)strlen(p->azColumn[iCol]); for(i=0; iazColumn[iCol], zNot, n) ){ + if( zNot && n==(int)strlen(zNot) + && 0==sqlite3_strnicmp(p->azColumn[iCol], zNot, n) + ){ p->abNotindexed[iCol] = 1; sqlite3_free(zNot); azNotindexed[i] = 0; @@ -126067,10 +128245,7 @@ static int fts3InitVtab( ** addition of a %_stat table so that it can use incremental merge. */ if( !isFts4 && !isCreate ){ - int rc2 = SQLITE_OK; - fts3DbExec(&rc2, db, "SELECT 1 FROM %Q.'%q_stat' WHERE id=2", - p->zDb, p->zName); - if( rc2==SQLITE_OK ) p->bHasStat = 1; + p->bHasStat = 2; } /* Figure out the page-size for the database. This is required in order to @@ -127962,7 +130137,10 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){ Fts3Table *p = (Fts3Table*)pVtab; int rc = sqlite3Fts3PendingTermsFlush(p); - if( rc==SQLITE_OK && p->bAutoincrmerge==1 && p->nLeafAdd>(nMinMerge/16) ){ + if( rc==SQLITE_OK + && p->nLeafAdd>(nMinMerge/16) + && p->nAutoincrmerge && p->nAutoincrmerge!=0xff + ){ int mxLevel = 0; /* Maximum relative level value in db */ int A; /* Incr-merge parameter A */ @@ -127970,14 +130148,41 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){ assert( rc==SQLITE_OK || mxLevel==0 ); A = p->nLeafAdd * mxLevel; A += (A/2); - if( A>(int)nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, 8); + if( A>(int)nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, p->nAutoincrmerge); } sqlite3Fts3SegmentsClose(p); return rc; } /* -** Implementation of xBegin() method. This is a no-op. +** If it is currently unknown whether or not the FTS table has an %_stat +** table (if p->bHasStat==2), attempt to determine this (set p->bHasStat +** to 0 or 1). Return SQLITE_OK if successful, or an SQLite error code +** if an error occurs. +*/ +static int fts3SetHasStat(Fts3Table *p){ + int rc = SQLITE_OK; + if( p->bHasStat==2 ){ + const char *zFmt ="SELECT 1 FROM %Q.sqlite_master WHERE tbl_name='%q_stat'"; + char *zSql = sqlite3_mprintf(zFmt, p->zDb, p->zName); + if( zSql ){ + sqlite3_stmt *pStmt = 0; + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + if( rc==SQLITE_OK ){ + int bHasStat = (sqlite3_step(pStmt)==SQLITE_ROW); + rc = sqlite3_finalize(pStmt); + if( rc==SQLITE_OK ) p->bHasStat = bHasStat; + } + sqlite3_free(zSql); + }else{ + rc = SQLITE_NOMEM; + } + } + return rc; +} + +/* +** Implementation of xBegin() method. */ static int fts3BeginMethod(sqlite3_vtab *pVtab){ Fts3Table *p = (Fts3Table*)pVtab; @@ -127988,7 +130193,7 @@ static int fts3BeginMethod(sqlite3_vtab *pVtab){ TESTONLY( p->inTransaction = 1 ); TESTONLY( p->mxSavepoint = -1; ); p->nLeafAdd = 0; - return SQLITE_OK; + return fts3SetHasStat(p); } /* @@ -128237,6 +130442,10 @@ static int fts3RenameMethod( sqlite3 *db = p->db; /* Database connection */ int rc; /* Return Code */ + /* At this point it must be known if the %_stat table exists or not. + ** So bHasStat may not be 2. */ + rc = fts3SetHasStat(p); + /* As it happens, the pending terms table is always empty here. This is ** because an "ALTER TABLE RENAME TABLE" statement inside a transaction ** always opens a savepoint transaction. And the xSavepoint() method @@ -128244,7 +130453,9 @@ static int fts3RenameMethod( ** PendingTermsFlush() in in case that changes. */ assert( p->nPendingData==0 ); - rc = sqlite3Fts3PendingTermsFlush(p); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts3PendingTermsFlush(p); + } if( p->zContentTbl==0 ){ fts3DbExec(&rc, db, @@ -128372,7 +130583,7 @@ static void hashDestroy(void *p){ */ SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule); SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(sqlite3_tokenizer_module const**ppModule); -#ifdef SQLITE_ENABLE_FTS4_UNICODE61 +#ifndef SQLITE_DISABLE_FTS3_UNICODE SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const**ppModule); #endif #ifdef SQLITE_ENABLE_ICU @@ -128390,7 +130601,7 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){ Fts3Hash *pHash = 0; const sqlite3_tokenizer_module *pSimple = 0; const sqlite3_tokenizer_module *pPorter = 0; -#ifdef SQLITE_ENABLE_FTS4_UNICODE61 +#ifndef SQLITE_DISABLE_FTS3_UNICODE const sqlite3_tokenizer_module *pUnicode = 0; #endif @@ -128399,7 +130610,7 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){ sqlite3Fts3IcuTokenizerModule(&pIcu); #endif -#ifdef SQLITE_ENABLE_FTS4_UNICODE61 +#ifndef SQLITE_DISABLE_FTS3_UNICODE sqlite3Fts3UnicodeTokenizer(&pUnicode); #endif @@ -128427,7 +130638,7 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){ if( sqlite3Fts3HashInsert(pHash, "simple", 7, (void *)pSimple) || sqlite3Fts3HashInsert(pHash, "porter", 7, (void *)pPorter) -#ifdef SQLITE_ENABLE_FTS4_UNICODE61 +#ifndef SQLITE_DISABLE_FTS3_UNICODE || sqlite3Fts3HashInsert(pHash, "unicode61", 10, (void *)pUnicode) #endif #ifdef SQLITE_ENABLE_ICU @@ -131160,40 +133371,23 @@ static int getNextToken( int rc; sqlite3_tokenizer_cursor *pCursor; Fts3Expr *pRet = 0; - int nConsumed = 0; + int i = 0; - rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, n, &pCursor); + /* Set variable i to the maximum number of bytes of input to tokenize. */ + for(i=0; iiLangid, z, i, &pCursor); if( rc==SQLITE_OK ){ const char *zToken; int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0; int nByte; /* total space to allocate */ rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition); - - if( (rc==SQLITE_OK || rc==SQLITE_DONE) && sqlite3_fts3_enable_parentheses ){ - int i; - if( rc==SQLITE_DONE ) iStart = n; - for(i=0; inNest++; - rc = fts3ExprParse(pParse, &z[i+1], n-i-1, &pRet, &nConsumed); - if( rc==SQLITE_OK && !pRet ){ - rc = SQLITE_DONE; - } - nConsumed = (int)(i + 1 + nConsumed); - break; - } - - if( z[i]==')' ){ - rc = SQLITE_DONE; - pParse->nNest--; - nConsumed = i+1; - break; - } - } - } - - if( nConsumed==0 && rc==SQLITE_OK ){ + if( rc==SQLITE_OK ){ nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken; pRet = (Fts3Expr *)fts3MallocZero(nByte); if( !pRet ){ @@ -131227,13 +133421,14 @@ static int getNextToken( } } - nConsumed = iEnd; + *pnConsumed = iEnd; + }else if( i && rc==SQLITE_DONE ){ + rc = SQLITE_OK; } pModule->xClose(pCursor); } - *pnConsumed = nConsumed; *ppExpr = pRet; return rc; } @@ -131483,6 +133678,21 @@ static int getNextNode( return getNextString(pParse, &zInput[1], ii-1, ppExpr); } + if( sqlite3_fts3_enable_parentheses ){ + if( *zInput=='(' ){ + int nConsumed = 0; + pParse->nNest++; + rc = fts3ExprParse(pParse, zInput+1, nInput-1, ppExpr, &nConsumed); + if( rc==SQLITE_OK && !*ppExpr ){ rc = SQLITE_DONE; } + *pnConsumed = (int)(zInput - z) + 1 + nConsumed; + return rc; + }else if( *zInput==')' ){ + pParse->nNest--; + *pnConsumed = (int)((zInput - z) + 1); + *ppExpr = 0; + return SQLITE_DONE; + } + } /* If control flows to this point, this must be a regular token, or ** the end of the input. Read a regular token using the sqlite3_tokenizer @@ -131601,96 +133811,100 @@ static int fts3ExprParse( while( rc==SQLITE_OK ){ Fts3Expr *p = 0; int nByte = 0; + rc = getNextNode(pParse, zIn, nIn, &p, &nByte); + assert( nByte>0 || (rc!=SQLITE_OK && p==0) ); if( rc==SQLITE_OK ){ - int isPhrase; + if( p ){ + int isPhrase; - if( !sqlite3_fts3_enable_parentheses - && p->eType==FTSQUERY_PHRASE && pParse->isNot - ){ - /* Create an implicit NOT operator. */ - Fts3Expr *pNot = fts3MallocZero(sizeof(Fts3Expr)); - if( !pNot ){ - sqlite3Fts3ExprFree(p); - rc = SQLITE_NOMEM; - goto exprparse_out; - } - pNot->eType = FTSQUERY_NOT; - pNot->pRight = p; - p->pParent = pNot; - if( pNotBranch ){ - pNot->pLeft = pNotBranch; - pNotBranch->pParent = pNot; - } - pNotBranch = pNot; - p = pPrev; - }else{ - int eType = p->eType; - isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft); - - /* The isRequirePhrase variable is set to true if a phrase or - ** an expression contained in parenthesis is required. If a - ** binary operator (AND, OR, NOT or NEAR) is encounted when - ** isRequirePhrase is set, this is a syntax error. - */ - if( !isPhrase && isRequirePhrase ){ - sqlite3Fts3ExprFree(p); - rc = SQLITE_ERROR; - goto exprparse_out; - } - - if( isPhrase && !isRequirePhrase ){ - /* Insert an implicit AND operator. */ - Fts3Expr *pAnd; - assert( pRet && pPrev ); - pAnd = fts3MallocZero(sizeof(Fts3Expr)); - if( !pAnd ){ + if( !sqlite3_fts3_enable_parentheses + && p->eType==FTSQUERY_PHRASE && pParse->isNot + ){ + /* Create an implicit NOT operator. */ + Fts3Expr *pNot = fts3MallocZero(sizeof(Fts3Expr)); + if( !pNot ){ sqlite3Fts3ExprFree(p); rc = SQLITE_NOMEM; goto exprparse_out; } - pAnd->eType = FTSQUERY_AND; - insertBinaryOperator(&pRet, pPrev, pAnd); - pPrev = pAnd; - } + pNot->eType = FTSQUERY_NOT; + pNot->pRight = p; + p->pParent = pNot; + if( pNotBranch ){ + pNot->pLeft = pNotBranch; + pNotBranch->pParent = pNot; + } + pNotBranch = pNot; + p = pPrev; + }else{ + int eType = p->eType; + isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft); - /* This test catches attempts to make either operand of a NEAR - ** operator something other than a phrase. For example, either of - ** the following: - ** - ** (bracketed expression) NEAR phrase - ** phrase NEAR (bracketed expression) - ** - ** Return an error in either case. - */ - if( pPrev && ( + /* The isRequirePhrase variable is set to true if a phrase or + ** an expression contained in parenthesis is required. If a + ** binary operator (AND, OR, NOT or NEAR) is encounted when + ** isRequirePhrase is set, this is a syntax error. + */ + if( !isPhrase && isRequirePhrase ){ + sqlite3Fts3ExprFree(p); + rc = SQLITE_ERROR; + goto exprparse_out; + } + + if( isPhrase && !isRequirePhrase ){ + /* Insert an implicit AND operator. */ + Fts3Expr *pAnd; + assert( pRet && pPrev ); + pAnd = fts3MallocZero(sizeof(Fts3Expr)); + if( !pAnd ){ + sqlite3Fts3ExprFree(p); + rc = SQLITE_NOMEM; + goto exprparse_out; + } + pAnd->eType = FTSQUERY_AND; + insertBinaryOperator(&pRet, pPrev, pAnd); + pPrev = pAnd; + } + + /* This test catches attempts to make either operand of a NEAR + ** operator something other than a phrase. For example, either of + ** the following: + ** + ** (bracketed expression) NEAR phrase + ** phrase NEAR (bracketed expression) + ** + ** Return an error in either case. + */ + if( pPrev && ( (eType==FTSQUERY_NEAR && !isPhrase && pPrev->eType!=FTSQUERY_PHRASE) || (eType!=FTSQUERY_PHRASE && isPhrase && pPrev->eType==FTSQUERY_NEAR) - )){ - sqlite3Fts3ExprFree(p); - rc = SQLITE_ERROR; - goto exprparse_out; - } - - if( isPhrase ){ - if( pRet ){ - assert( pPrev && pPrev->pLeft && pPrev->pRight==0 ); - pPrev->pRight = p; - p->pParent = pPrev; - }else{ - pRet = p; + )){ + sqlite3Fts3ExprFree(p); + rc = SQLITE_ERROR; + goto exprparse_out; } - }else{ - insertBinaryOperator(&pRet, pPrev, p); + + if( isPhrase ){ + if( pRet ){ + assert( pPrev && pPrev->pLeft && pPrev->pRight==0 ); + pPrev->pRight = p; + p->pParent = pPrev; + }else{ + pRet = p; + } + }else{ + insertBinaryOperator(&pRet, pPrev, p); + } + isRequirePhrase = !isPhrase; } - isRequirePhrase = !isPhrase; + pPrev = p; } assert( nByte>0 ); } assert( rc!=SQLITE_OK || (nByte>0 && nByte<=nIn) ); nIn -= nByte; zIn += nByte; - pPrev = p; } if( rc==SQLITE_DONE && pRet && isRequirePhrase ){ @@ -134678,6 +136892,7 @@ struct SegmentWriter { int nSize; /* Size of allocation at aData */ int nData; /* Bytes of data in aData */ char *aData; /* Pointer to block from malloc() */ + i64 nLeafData; /* Number of bytes of leaf data written */ }; /* @@ -134753,6 +136968,10 @@ struct SegmentNode { #define SQL_SELECT_INDEXES 35 #define SQL_SELECT_MXLEVEL 36 +#define SQL_SELECT_LEVEL_RANGE2 37 +#define SQL_UPDATE_LEVEL_IDX 38 +#define SQL_UPDATE_LEVEL 39 + /* ** This function is used to obtain an SQLite prepared statement handle ** for the statement identified by the second argument. If successful, @@ -134854,7 +137073,18 @@ static int fts3SqlStmt( /* SQL_SELECT_MXLEVEL ** Return the largest relative level in the FTS index or indexes. */ -/* 36 */ "SELECT max( level %% 1024 ) FROM %Q.'%q_segdir'" +/* 36 */ "SELECT max( level %% 1024 ) FROM %Q.'%q_segdir'", + + /* Return segments in order from oldest to newest.*/ +/* 37 */ "SELECT level, idx, end_block " + "FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ? " + "ORDER BY level DESC, idx ASC", + + /* Update statements used while promoting segments */ +/* 38 */ "UPDATE OR FAIL %Q.'%q_segdir' SET level=-1,idx=? " + "WHERE level=? AND idx=?", +/* 39 */ "UPDATE OR FAIL %Q.'%q_segdir' SET level=? WHERE level=-1" + }; int rc = SQLITE_OK; sqlite3_stmt *pStmt; @@ -136395,6 +138625,7 @@ static int fts3WriteSegdir( sqlite3_int64 iStartBlock, /* Value for "start_block" field */ sqlite3_int64 iLeafEndBlock, /* Value for "leaves_end_block" field */ sqlite3_int64 iEndBlock, /* Value for "end_block" field */ + sqlite3_int64 nLeafData, /* Bytes of leaf data in segment */ char *zRoot, /* Blob value for "root" field */ int nRoot /* Number of bytes in buffer zRoot */ ){ @@ -136405,7 +138636,13 @@ static int fts3WriteSegdir( sqlite3_bind_int(pStmt, 2, iIdx); sqlite3_bind_int64(pStmt, 3, iStartBlock); sqlite3_bind_int64(pStmt, 4, iLeafEndBlock); - sqlite3_bind_int64(pStmt, 5, iEndBlock); + if( nLeafData==0 ){ + sqlite3_bind_int64(pStmt, 5, iEndBlock); + }else{ + char *zEnd = sqlite3_mprintf("%lld %lld", iEndBlock, nLeafData); + if( !zEnd ) return SQLITE_NOMEM; + sqlite3_bind_text(pStmt, 5, zEnd, -1, sqlite3_free); + } sqlite3_bind_blob(pStmt, 6, zRoot, nRoot, SQLITE_STATIC); sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); @@ -136731,6 +138968,9 @@ static int fts3SegWriterAdd( nDoclist; /* Doclist data */ } + /* Increase the total number of bytes written to account for the new entry. */ + pWriter->nLeafData += nReq; + /* If the buffer currently allocated is too small for this entry, realloc ** the buffer to make it large enough. */ @@ -136802,13 +139042,13 @@ static int fts3SegWriterFlush( pWriter->iFirst, pWriter->iFree, &iLast, &zRoot, &nRoot); } if( rc==SQLITE_OK ){ - rc = fts3WriteSegdir( - p, iLevel, iIdx, pWriter->iFirst, iLastLeaf, iLast, zRoot, nRoot); + rc = fts3WriteSegdir(p, iLevel, iIdx, + pWriter->iFirst, iLastLeaf, iLast, pWriter->nLeafData, zRoot, nRoot); } }else{ /* The entire tree fits on the root node. Write it to the segdir table. */ - rc = fts3WriteSegdir( - p, iLevel, iIdx, 0, 0, 0, pWriter->aData, pWriter->nData); + rc = fts3WriteSegdir(p, iLevel, iIdx, + 0, 0, 0, pWriter->nLeafData, pWriter->aData, pWriter->nData); } p->nLeafAdd++; return rc; @@ -136892,6 +139132,37 @@ static int fts3SegmentMaxLevel( return sqlite3_reset(pStmt); } +/* +** iAbsLevel is an absolute level that may be assumed to exist within +** the database. This function checks if it is the largest level number +** within its index. Assuming no error occurs, *pbMax is set to 1 if +** iAbsLevel is indeed the largest level, or 0 otherwise, and SQLITE_OK +** is returned. If an error occurs, an error code is returned and the +** final value of *pbMax is undefined. +*/ +static int fts3SegmentIsMaxLevel(Fts3Table *p, i64 iAbsLevel, int *pbMax){ + + /* Set pStmt to the compiled version of: + ** + ** SELECT max(level) FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ? + ** + ** (1024 is actually the value of macro FTS3_SEGDIR_PREFIXLEVEL_STR). + */ + sqlite3_stmt *pStmt; + int rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0); + if( rc!=SQLITE_OK ) return rc; + sqlite3_bind_int64(pStmt, 1, iAbsLevel+1); + sqlite3_bind_int64(pStmt, 2, + ((iAbsLevel/FTS3_SEGDIR_MAXLEVEL)+1) * FTS3_SEGDIR_MAXLEVEL + ); + + *pbMax = 0; + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + *pbMax = sqlite3_column_type(pStmt, 0)==SQLITE_NULL; + } + return sqlite3_reset(pStmt); +} + /* ** Delete all entries in the %_segments table associated with the segment ** opened with seg-reader pSeg. This function does not affect the contents @@ -137427,6 +139698,140 @@ SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish( } } +/* +** Decode the "end_block" field, selected by column iCol of the SELECT +** statement passed as the first argument. +** +** The "end_block" field may contain either an integer, or a text field +** containing the text representation of two non-negative integers separated +** by one or more space (0x20) characters. In the first case, set *piEndBlock +** to the integer value and *pnByte to zero before returning. In the second, +** set *piEndBlock to the first value and *pnByte to the second. +*/ +static void fts3ReadEndBlockField( + sqlite3_stmt *pStmt, + int iCol, + i64 *piEndBlock, + i64 *pnByte +){ + const unsigned char *zText = sqlite3_column_text(pStmt, iCol); + if( zText ){ + int i; + int iMul = 1; + i64 iVal = 0; + for(i=0; zText[i]>='0' && zText[i]<='9'; i++){ + iVal = iVal*10 + (zText[i] - '0'); + } + *piEndBlock = iVal; + while( zText[i]==' ' ) i++; + iVal = 0; + if( zText[i]=='-' ){ + i++; + iMul = -1; + } + for(/* no-op */; zText[i]>='0' && zText[i]<='9'; i++){ + iVal = iVal*10 + (zText[i] - '0'); + } + *pnByte = (iVal * (i64)iMul); + } +} + + +/* +** A segment of size nByte bytes has just been written to absolute level +** iAbsLevel. Promote any segments that should be promoted as a result. +*/ +static int fts3PromoteSegments( + Fts3Table *p, /* FTS table handle */ + sqlite3_int64 iAbsLevel, /* Absolute level just updated */ + sqlite3_int64 nByte /* Size of new segment at iAbsLevel */ +){ + int rc = SQLITE_OK; + sqlite3_stmt *pRange; + + rc = fts3SqlStmt(p, SQL_SELECT_LEVEL_RANGE2, &pRange, 0); + + if( rc==SQLITE_OK ){ + int bOk = 0; + i64 iLast = (iAbsLevel/FTS3_SEGDIR_MAXLEVEL + 1) * FTS3_SEGDIR_MAXLEVEL - 1; + i64 nLimit = (nByte*3)/2; + + /* Loop through all entries in the %_segdir table corresponding to + ** segments in this index on levels greater than iAbsLevel. If there is + ** at least one such segment, and it is possible to determine that all + ** such segments are smaller than nLimit bytes in size, they will be + ** promoted to level iAbsLevel. */ + sqlite3_bind_int64(pRange, 1, iAbsLevel+1); + sqlite3_bind_int64(pRange, 2, iLast); + while( SQLITE_ROW==sqlite3_step(pRange) ){ + i64 nSize = 0, dummy; + fts3ReadEndBlockField(pRange, 2, &dummy, &nSize); + if( nSize<=0 || nSize>nLimit ){ + /* If nSize==0, then the %_segdir.end_block field does not not + ** contain a size value. This happens if it was written by an + ** old version of FTS. In this case it is not possible to determine + ** the size of the segment, and so segment promotion does not + ** take place. */ + bOk = 0; + break; + } + bOk = 1; + } + rc = sqlite3_reset(pRange); + + if( bOk ){ + int iIdx = 0; + sqlite3_stmt *pUpdate1; + sqlite3_stmt *pUpdate2; + + if( rc==SQLITE_OK ){ + rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL_IDX, &pUpdate1, 0); + } + if( rc==SQLITE_OK ){ + rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL, &pUpdate2, 0); + } + + if( rc==SQLITE_OK ){ + + /* Loop through all %_segdir entries for segments in this index with + ** levels equal to or greater than iAbsLevel. As each entry is visited, + ** updated it to set (level = -1) and (idx = N), where N is 0 for the + ** oldest segment in the range, 1 for the next oldest, and so on. + ** + ** In other words, move all segments being promoted to level -1, + ** setting the "idx" fields as appropriate to keep them in the same + ** order. The contents of level -1 (which is never used, except + ** transiently here), will be moved back to level iAbsLevel below. */ + sqlite3_bind_int64(pRange, 1, iAbsLevel); + while( SQLITE_ROW==sqlite3_step(pRange) ){ + sqlite3_bind_int(pUpdate1, 1, iIdx++); + sqlite3_bind_int(pUpdate1, 2, sqlite3_column_int(pRange, 0)); + sqlite3_bind_int(pUpdate1, 3, sqlite3_column_int(pRange, 1)); + sqlite3_step(pUpdate1); + rc = sqlite3_reset(pUpdate1); + if( rc!=SQLITE_OK ){ + sqlite3_reset(pRange); + break; + } + } + } + if( rc==SQLITE_OK ){ + rc = sqlite3_reset(pRange); + } + + /* Move level -1 to level iAbsLevel */ + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pUpdate2, 1, iAbsLevel); + sqlite3_step(pUpdate2); + rc = sqlite3_reset(pUpdate2); + } + } + } + + + return rc; +} + /* ** Merge all level iLevel segments in the database into a single ** iLevel+1 segment. Or, if iLevel<0, merge all segments into a @@ -137451,6 +139856,7 @@ static int fts3SegmentMerge( Fts3SegFilter filter; /* Segment term filter condition */ Fts3MultiSegReader csr; /* Cursor to iterate through level(s) */ int bIgnoreEmpty = 0; /* True to ignore empty segments */ + i64 iMaxLevel = 0; /* Max level number for this index/langid */ assert( iLevel==FTS3_SEGCURSOR_ALL || iLevel==FTS3_SEGCURSOR_PENDING @@ -137462,6 +139868,11 @@ static int fts3SegmentMerge( rc = sqlite3Fts3SegReaderCursor(p, iLangid, iIndex, iLevel, 0, 0, 1, 0, &csr); if( rc!=SQLITE_OK || csr.nSegment==0 ) goto finished; + if( iLevel!=FTS3_SEGCURSOR_PENDING ){ + rc = fts3SegmentMaxLevel(p, iLangid, iIndex, &iMaxLevel); + if( rc!=SQLITE_OK ) goto finished; + } + if( iLevel==FTS3_SEGCURSOR_ALL ){ /* This call is to merge all segments in the database to a single ** segment. The level of the new segment is equal to the numerically @@ -137471,21 +139882,21 @@ static int fts3SegmentMerge( rc = SQLITE_DONE; goto finished; } - rc = fts3SegmentMaxLevel(p, iLangid, iIndex, &iNewLevel); + iNewLevel = iMaxLevel; bIgnoreEmpty = 1; - }else if( iLevel==FTS3_SEGCURSOR_PENDING ){ - iNewLevel = getAbsoluteLevel(p, iLangid, iIndex, 0); - rc = fts3AllocateSegdirIdx(p, iLangid, iIndex, 0, &iIdx); }else{ /* This call is to merge all segments at level iLevel. find the next ** available segment index at level iLevel+1. The call to ** fts3AllocateSegdirIdx() will merge the segments at level iLevel+1 to ** a single iLevel+2 segment if necessary. */ - rc = fts3AllocateSegdirIdx(p, iLangid, iIndex, iLevel+1, &iIdx); + assert( FTS3_SEGCURSOR_PENDING==-1 ); iNewLevel = getAbsoluteLevel(p, iLangid, iIndex, iLevel+1); + rc = fts3AllocateSegdirIdx(p, iLangid, iIndex, iLevel+1, &iIdx); + bIgnoreEmpty = (iLevel!=FTS3_SEGCURSOR_PENDING) && (iNewLevel>iMaxLevel); } if( rc!=SQLITE_OK ) goto finished; + assert( csr.nSegment>0 ); assert( iNewLevel>=getAbsoluteLevel(p, iLangid, iIndex, 0) ); assert( iNewLevelnLeafData); + } + } + } finished: fts3SegWriterFree(pWriter); @@ -137520,7 +139938,7 @@ static int fts3SegmentMerge( /* -** Flush the contents of pendingTerms to level 0 segments. +** Flush the contents of pendingTerms to level 0 segments. */ SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){ int rc = SQLITE_OK; @@ -137536,14 +139954,19 @@ SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){ ** estimate the number of leaf blocks of content to be written */ if( rc==SQLITE_OK && p->bHasStat - && p->bAutoincrmerge==0xff && p->nLeafAdd>0 + && p->nAutoincrmerge==0xff && p->nLeafAdd>0 ){ sqlite3_stmt *pStmt = 0; rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pStmt, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE); rc = sqlite3_step(pStmt); - p->bAutoincrmerge = (rc==SQLITE_ROW && sqlite3_column_int(pStmt, 0)); + if( rc==SQLITE_ROW ){ + p->nAutoincrmerge = sqlite3_column_int(pStmt, 0); + if( p->nAutoincrmerge==1 ) p->nAutoincrmerge = 8; + }else if( rc==SQLITE_DONE ){ + p->nAutoincrmerge = 0; + } rc = sqlite3_reset(pStmt); } } @@ -137911,6 +140334,8 @@ struct IncrmergeWriter { int iIdx; /* Index of *output* segment in iAbsLevel+1 */ sqlite3_int64 iStart; /* Block number of first allocated block */ sqlite3_int64 iEnd; /* Block number of last allocated block */ + sqlite3_int64 nLeafData; /* Bytes of leaf page data so far */ + u8 bNoLeafData; /* If true, store 0 for segment size */ NodeWriter aNodeWriter[FTS_MAX_APPENDABLE_HEIGHT]; }; @@ -138249,8 +140674,8 @@ static int fts3IncrmergeAppend( nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist; } + pWriter->nLeafData += nSpace; blobGrowBuffer(&pLeaf->block, pLeaf->block.n + nSpace, &rc); - if( rc==SQLITE_OK ){ if( pLeaf->block.n==0 ){ pLeaf->block.n = 1; @@ -138349,6 +140774,7 @@ static void fts3IncrmergeRelease( pWriter->iStart, /* start_block */ pWriter->aNodeWriter[0].iBlock, /* leaves_end_block */ pWriter->iEnd, /* end_block */ + (pWriter->bNoLeafData==0 ? pWriter->nLeafData : 0), /* end_block */ pRoot->block.a, pRoot->block.n /* root */ ); } @@ -138450,7 +140876,11 @@ static int fts3IncrmergeLoad( if( sqlite3_step(pSelect)==SQLITE_ROW ){ iStart = sqlite3_column_int64(pSelect, 1); iLeafEnd = sqlite3_column_int64(pSelect, 2); - iEnd = sqlite3_column_int64(pSelect, 3); + fts3ReadEndBlockField(pSelect, 3, &iEnd, &pWriter->nLeafData); + if( pWriter->nLeafData<0 ){ + pWriter->nLeafData = pWriter->nLeafData * -1; + } + pWriter->bNoLeafData = (pWriter->nLeafData==0); nRoot = sqlite3_column_bytes(pSelect, 4); aRoot = sqlite3_column_blob(pSelect, 4); }else{ @@ -139051,11 +141481,11 @@ static int fts3IncrmergeHintPop(Blob *pHint, i64 *piAbsLevel, int *pnInput){ /* ** Attempt an incremental merge that writes nMerge leaf blocks. ** -** Incremental merges happen nMin segments at a time. The two -** segments to be merged are the nMin oldest segments (the ones with -** the smallest indexes) in the highest level that contains at least -** nMin segments. Multiple merges might occur in an attempt to write the -** quota of nMerge leaf blocks. +** Incremental merges happen nMin segments at a time. The segments +** to be merged are the nMin oldest segments (the ones with the smallest +** values for the _segdir.idx field) in the highest level that contains +** at least nMin segments. Multiple merges might occur in an attempt to +** write the quota of nMerge leaf blocks. */ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){ int rc; /* Return code */ @@ -139080,6 +141510,7 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){ const i64 nMod = FTS3_SEGDIR_MAXLEVEL * p->nIndex; sqlite3_stmt *pFindLevel = 0; /* SQL used to determine iAbsLevel */ int bUseHint = 0; /* True if attempting to append */ + int iIdx = 0; /* Largest idx in level (iAbsLevel+1) */ /* Search the %_segdir table for the absolute level with the smallest ** relative level number that contains at least nMin segments, if any. @@ -139133,6 +141564,19 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){ ** to start work on some other level. */ memset(pWriter, 0, nAlloc); pFilter->flags = FTS3_SEGMENT_REQUIRE_POS; + + if( rc==SQLITE_OK ){ + rc = fts3IncrmergeOutputIdx(p, iAbsLevel, &iIdx); + assert( bUseHint==1 || bUseHint==0 ); + if( iIdx==0 || (bUseHint && iIdx==1) ){ + int bIgnore = 0; + rc = fts3SegmentIsMaxLevel(p, iAbsLevel+1, &bIgnore); + if( bIgnore ){ + pFilter->flags |= FTS3_SEGMENT_IGNORE_EMPTY; + } + } + } + if( rc==SQLITE_OK ){ rc = fts3IncrmergeCsr(p, iAbsLevel, nSeg, pCsr); } @@ -139140,16 +141584,12 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){ && SQLITE_OK==(rc = sqlite3Fts3SegReaderStart(p, pCsr, pFilter)) && SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, pCsr)) ){ - int iIdx = 0; /* Largest idx in level (iAbsLevel+1) */ - rc = fts3IncrmergeOutputIdx(p, iAbsLevel, &iIdx); - if( rc==SQLITE_OK ){ - if( bUseHint && iIdx>0 ){ - const char *zKey = pCsr->zTerm; - int nKey = pCsr->nTerm; - rc = fts3IncrmergeLoad(p, iAbsLevel, iIdx-1, zKey, nKey, pWriter); - }else{ - rc = fts3IncrmergeWriter(p, iAbsLevel, iIdx, pCsr, pWriter); - } + if( bUseHint && iIdx>0 ){ + const char *zKey = pCsr->zTerm; + int nKey = pCsr->nTerm; + rc = fts3IncrmergeLoad(p, iAbsLevel, iIdx-1, zKey, nKey, pWriter); + }else{ + rc = fts3IncrmergeWriter(p, iAbsLevel, iIdx, pCsr, pWriter); } if( rc==SQLITE_OK && pWriter->nLeafEst ){ @@ -139171,7 +141611,13 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){ } } + if( nSeg!=0 ){ + pWriter->nLeafData = pWriter->nLeafData * -1; + } fts3IncrmergeRelease(p, pWriter, &rc); + if( nSeg==0 && pWriter->bNoLeafData==0 ){ + fts3PromoteSegments(p, iAbsLevel+1, pWriter->nLeafData); + } } sqlite3Fts3SegReaderFinish(pCsr); @@ -139258,7 +141704,10 @@ static int fts3DoAutoincrmerge( ){ int rc = SQLITE_OK; sqlite3_stmt *pStmt = 0; - p->bAutoincrmerge = fts3Getint(&zParam)!=0; + p->nAutoincrmerge = fts3Getint(&zParam); + if( p->nAutoincrmerge==1 || p->nAutoincrmerge>FTS3_MERGE_COUNT ){ + p->nAutoincrmerge = 8; + } if( !p->bHasStat ){ assert( p->bFts4==0 ); sqlite3Fts3CreateStatTable(&rc, p); @@ -139267,7 +141716,7 @@ static int fts3DoAutoincrmerge( rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pStmt, 0); if( rc ) return rc; sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE); - sqlite3_bind_int(pStmt, 2, p->bAutoincrmerge); + sqlite3_bind_int(pStmt, 2, p->nAutoincrmerge); sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); return rc; @@ -139424,34 +141873,36 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){ int iCol; for(iCol=0; rc==SQLITE_OK && iColnColumn; iCol++){ - const char *zText = (const char *)sqlite3_column_text(pStmt, iCol+1); - int nText = sqlite3_column_bytes(pStmt, iCol+1); - sqlite3_tokenizer_cursor *pT = 0; + if( p->abNotindexed[iCol]==0 ){ + const char *zText = (const char *)sqlite3_column_text(pStmt, iCol+1); + int nText = sqlite3_column_bytes(pStmt, iCol+1); + sqlite3_tokenizer_cursor *pT = 0; - rc = sqlite3Fts3OpenTokenizer(p->pTokenizer, iLang, zText, nText, &pT); - while( rc==SQLITE_OK ){ - char const *zToken; /* Buffer containing token */ - int nToken = 0; /* Number of bytes in token */ - int iDum1 = 0, iDum2 = 0; /* Dummy variables */ - int iPos = 0; /* Position of token in zText */ + rc = sqlite3Fts3OpenTokenizer(p->pTokenizer, iLang, zText, nText,&pT); + while( rc==SQLITE_OK ){ + char const *zToken; /* Buffer containing token */ + int nToken = 0; /* Number of bytes in token */ + int iDum1 = 0, iDum2 = 0; /* Dummy variables */ + int iPos = 0; /* Position of token in zText */ - rc = pModule->xNext(pT, &zToken, &nToken, &iDum1, &iDum2, &iPos); - if( rc==SQLITE_OK ){ - int i; - cksum2 = cksum2 ^ fts3ChecksumEntry( - zToken, nToken, iLang, 0, iDocid, iCol, iPos - ); - for(i=1; inIndex; i++){ - if( p->aIndex[i].nPrefix<=nToken ){ - cksum2 = cksum2 ^ fts3ChecksumEntry( - zToken, p->aIndex[i].nPrefix, iLang, i, iDocid, iCol, iPos - ); + rc = pModule->xNext(pT, &zToken, &nToken, &iDum1, &iDum2, &iPos); + if( rc==SQLITE_OK ){ + int i; + cksum2 = cksum2 ^ fts3ChecksumEntry( + zToken, nToken, iLang, 0, iDocid, iCol, iPos + ); + for(i=1; inIndex; i++){ + if( p->aIndex[i].nPrefix<=nToken ){ + cksum2 = cksum2 ^ fts3ChecksumEntry( + zToken, p->aIndex[i].nPrefix, iLang, i, iDocid, iCol, iPos + ); + } } } } + if( pT ) pModule->xClose(pT); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; } - if( pT ) pModule->xClose(pT); - if( rc==SQLITE_DONE ) rc = SQLITE_OK; } } @@ -139756,6 +142207,10 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod( int nChng = 0; /* Net change in number of documents */ int bInsertDone = 0; + /* At this point it must be known if the %_stat table exists or not. + ** So bHasStat may not be 2. */ + assert( p->bHasStat==0 || p->bHasStat==1 ); + assert( p->pSegments==0 ); assert( nArg==1 /* DELETE operations */ @@ -141443,7 +143898,7 @@ SQLITE_PRIVATE void sqlite3Fts3Matchinfo( ** Implementation of the "unicode" full-text-search tokenizer. */ -#ifdef SQLITE_ENABLE_FTS4_UNICODE61 +#ifndef SQLITE_DISABLE_FTS3_UNICODE #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) @@ -141659,7 +144114,7 @@ static int unicodeCreate( for(i=0; rc==SQLITE_OK && ibRemoveDiacritic = 1; @@ -141746,7 +144201,7 @@ static int unicodeNext( ){ unicode_cursor *pCsr = (unicode_cursor *)pC; unicode_tokenizer *p = ((unicode_tokenizer *)pCsr->base.pTokenizer); - int iCode; + int iCode = 0; char *zOut; const unsigned char *z = &pCsr->aInput[pCsr->iOff]; const unsigned char *zStart = z; @@ -141791,11 +144246,11 @@ static int unicodeNext( ); /* Set the output variables and return. */ - pCsr->iOff = (z - pCsr->aInput); + pCsr->iOff = (int)(z - pCsr->aInput); *paToken = pCsr->zToken; - *pnToken = zOut - pCsr->zToken; - *piStart = (zStart - pCsr->aInput); - *piEnd = (zEnd - pCsr->aInput); + *pnToken = (int)(zOut - pCsr->zToken); + *piStart = (int)(zStart - pCsr->aInput); + *piEnd = (int)(zEnd - pCsr->aInput); *piPos = pCsr->iToken++; return SQLITE_OK; } @@ -141818,7 +144273,7 @@ SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const * } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ -#endif /* ifndef SQLITE_ENABLE_FTS4_UNICODE61 */ +#endif /* ifndef SQLITE_DISABLE_FTS3_UNICODE */ /************** End of fts3_unicode.c ****************************************/ /************** Begin file fts3_unicode2.c ***********************************/ @@ -141839,7 +144294,7 @@ SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const * ** DO NOT EDIT THIS MACHINE GENERATED FILE. */ -#if defined(SQLITE_ENABLE_FTS4_UNICODE61) +#ifndef SQLITE_DISABLE_FTS3_UNICODE #if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) /* #include */ @@ -141863,7 +144318,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int c){ ** C. It is not possible to represent a range larger than 1023 codepoints ** using this format. */ - const static unsigned int aEntry[] = { + static const unsigned int aEntry[] = { 0x00000030, 0x0000E807, 0x00016C06, 0x0001EC2F, 0x0002AC07, 0x0002D001, 0x0002D803, 0x0002EC01, 0x0002FC01, 0x00035C01, 0x0003DC01, 0x000B0804, 0x000B480E, 0x000B9407, 0x000BB401, @@ -141955,7 +144410,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int c){ return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 ); }else if( c<(1<<22) ){ unsigned int key = (((unsigned int)c)<<10) | 0x000003FF; - int iRes; + int iRes = 0; int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; int iLo = 0; while( iHi>=iLo ){ @@ -142026,7 +144481,7 @@ static int remove_diacritic(int c){ } assert( key>=aDia[iRes] ); return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]); -}; +} /* @@ -142186,7 +144641,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){ return ret; } #endif /* defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) */ -#endif /* !defined(SQLITE_ENABLE_FTS4_UNICODE61) */ +#endif /* !defined(SQLITE_DISABLE_FTS3_UNICODE) */ /************** End of fts3_unicode2.c ***************************************/ /************** Begin file rtree.c *******************************************/ @@ -142246,48 +144701,6 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RTREE) -/* -** This file contains an implementation of a couple of different variants -** of the r-tree algorithm. See the README file for further details. The -** same data-structure is used for all, but the algorithms for insert and -** delete operations vary. The variants used are selected at compile time -** by defining the following symbols: -*/ - -/* Either, both or none of the following may be set to activate -** r*tree variant algorithms. -*/ -#define VARIANT_RSTARTREE_CHOOSESUBTREE 0 -#define VARIANT_RSTARTREE_REINSERT 1 - -/* -** Exactly one of the following must be set to 1. -*/ -#define VARIANT_GUTTMAN_QUADRATIC_SPLIT 0 -#define VARIANT_GUTTMAN_LINEAR_SPLIT 0 -#define VARIANT_RSTARTREE_SPLIT 1 - -#define VARIANT_GUTTMAN_SPLIT \ - (VARIANT_GUTTMAN_LINEAR_SPLIT||VARIANT_GUTTMAN_QUADRATIC_SPLIT) - -#if VARIANT_GUTTMAN_QUADRATIC_SPLIT - #define PickNext QuadraticPickNext - #define PickSeeds QuadraticPickSeeds - #define AssignCells splitNodeGuttman -#endif -#if VARIANT_GUTTMAN_LINEAR_SPLIT - #define PickNext LinearPickNext - #define PickSeeds LinearPickSeeds - #define AssignCells splitNodeGuttman -#endif -#if VARIANT_RSTARTREE_SPLIT - #define AssignCells splitNodeStartree -#endif - -#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) -# define NDEBUG 1 -#endif - #ifndef SQLITE_CORE SQLITE_EXTENSION_INIT1 #else @@ -142295,11 +144708,13 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){ /* #include */ /* #include */ +/* #include */ #ifndef SQLITE_AMALGAMATION #include "sqlite3rtree.h" typedef sqlite3_int64 i64; typedef unsigned char u8; +typedef unsigned short u16; typedef unsigned int u32; #endif @@ -142317,6 +144732,7 @@ typedef struct RtreeConstraint RtreeConstraint; typedef struct RtreeMatchArg RtreeMatchArg; typedef struct RtreeGeomCallback RtreeGeomCallback; typedef union RtreeCoord RtreeCoord; +typedef struct RtreeSearchPoint RtreeSearchPoint; /* The rtree may have between 1 and RTREE_MAX_DIMENSIONS dimensions. */ #define RTREE_MAX_DIMENSIONS 5 @@ -142325,7 +144741,7 @@ typedef union RtreeCoord RtreeCoord; ** ever contain very many entries, so a fixed number of buckets is ** used. */ -#define HASHSIZE 128 +#define HASHSIZE 97 /* The xBestIndex method of this virtual table requires an estimate of ** the number of rows in the virtual table to calculate the costs of @@ -142341,15 +144757,15 @@ typedef union RtreeCoord RtreeCoord; ** An rtree virtual-table object. */ struct Rtree { - sqlite3_vtab base; + sqlite3_vtab base; /* Base class. Must be first */ sqlite3 *db; /* Host database connection */ int iNodeSize; /* Size in bytes of each node in the node table */ - int nDim; /* Number of dimensions */ - int nBytesPerCell; /* Bytes consumed per cell */ + u8 nDim; /* Number of dimensions */ + u8 eCoordType; /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */ + u8 nBytesPerCell; /* Bytes consumed per cell */ int iDepth; /* Current depth of the r-tree structure */ char *zDb; /* Name of database containing r-tree table */ char *zName; /* Name of r-tree table */ - RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */ int nBusy; /* Current number of users of this structure */ i64 nRowEst; /* Estimated number of rows in this table */ @@ -142376,10 +144792,10 @@ struct Rtree { sqlite3_stmt *pWriteParent; sqlite3_stmt *pDeleteParent; - int eCoordType; + RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */ }; -/* Possible values for eCoordType: */ +/* Possible values for Rtree.eCoordType: */ #define RTREE_COORD_REAL32 0 #define RTREE_COORD_INT32 1 @@ -142391,11 +144807,30 @@ struct Rtree { #ifdef SQLITE_RTREE_INT_ONLY typedef sqlite3_int64 RtreeDValue; /* High accuracy coordinate */ typedef int RtreeValue; /* Low accuracy coordinate */ +# define RTREE_ZERO 0 #else typedef double RtreeDValue; /* High accuracy coordinate */ typedef float RtreeValue; /* Low accuracy coordinate */ +# define RTREE_ZERO 0.0 #endif +/* +** When doing a search of an r-tree, instances of the following structure +** record intermediate results from the tree walk. +** +** The id is always a node-id. For iLevel>=1 the id is the node-id of +** the node that the RtreeSearchPoint represents. When iLevel==0, however, +** the id is of the parent node and the cell that RtreeSearchPoint +** represents is the iCell-th entry in the parent node. +*/ +struct RtreeSearchPoint { + RtreeDValue rScore; /* The score for this node. Smallest goes first. */ + sqlite3_int64 id; /* Node ID */ + u8 iLevel; /* 0=entries. 1=leaf node. 2+ for higher */ + u8 eWithin; /* PARTLY_WITHIN or FULLY_WITHIN */ + u8 iCell; /* Cell index within the node */ +}; + /* ** The minimum number of cells allowed for a node is a third of the ** maximum. In Gutman's notation: @@ -142418,21 +144853,44 @@ struct Rtree { */ #define RTREE_MAX_DEPTH 40 + +/* +** Number of entries in the cursor RtreeNode cache. The first entry is +** used to cache the RtreeNode for RtreeCursor.sPoint. The remaining +** entries cache the RtreeNode for the first elements of the priority queue. +*/ +#define RTREE_CACHE_SZ 5 + /* ** An rtree cursor object. */ struct RtreeCursor { - sqlite3_vtab_cursor base; - RtreeNode *pNode; /* Node cursor is currently pointing at */ - int iCell; /* Index of current cell in pNode */ + sqlite3_vtab_cursor base; /* Base class. Must be first */ + u8 atEOF; /* True if at end of search */ + u8 bPoint; /* True if sPoint is valid */ int iStrategy; /* Copy of idxNum search parameter */ int nConstraint; /* Number of entries in aConstraint */ RtreeConstraint *aConstraint; /* Search constraints. */ + int nPointAlloc; /* Number of slots allocated for aPoint[] */ + int nPoint; /* Number of slots used in aPoint[] */ + int mxLevel; /* iLevel value for root of the tree */ + RtreeSearchPoint *aPoint; /* Priority queue for search points */ + RtreeSearchPoint sPoint; /* Cached next search point */ + RtreeNode *aNode[RTREE_CACHE_SZ]; /* Rtree node cache */ + u32 anQueue[RTREE_MAX_DEPTH+1]; /* Number of queued entries by iLevel */ }; +/* Return the Rtree of a RtreeCursor */ +#define RTREE_OF_CURSOR(X) ((Rtree*)((X)->base.pVtab)) + +/* +** A coordinate can be either a floating point number or a integer. All +** coordinates within a single R-Tree are always of the same time. +*/ union RtreeCoord { - RtreeValue f; - int i; + RtreeValue f; /* Floating point value */ + int i; /* Integer value */ + u32 u; /* Unsigned for byte-order conversions */ }; /* @@ -142457,38 +144915,67 @@ union RtreeCoord { struct RtreeConstraint { int iCoord; /* Index of constrained coordinate */ int op; /* Constraining operation */ - RtreeDValue rValue; /* Constraint value. */ - int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*); - sqlite3_rtree_geometry *pGeom; /* Constraint callback argument for a MATCH */ + union { + RtreeDValue rValue; /* Constraint value. */ + int (*xGeom)(sqlite3_rtree_geometry*,int,RtreeDValue*,int*); + int (*xQueryFunc)(sqlite3_rtree_query_info*); + } u; + sqlite3_rtree_query_info *pInfo; /* xGeom and xQueryFunc argument */ }; /* Possible values for RtreeConstraint.op */ -#define RTREE_EQ 0x41 -#define RTREE_LE 0x42 -#define RTREE_LT 0x43 -#define RTREE_GE 0x44 -#define RTREE_GT 0x45 -#define RTREE_MATCH 0x46 +#define RTREE_EQ 0x41 /* A */ +#define RTREE_LE 0x42 /* B */ +#define RTREE_LT 0x43 /* C */ +#define RTREE_GE 0x44 /* D */ +#define RTREE_GT 0x45 /* E */ +#define RTREE_MATCH 0x46 /* F: Old-style sqlite3_rtree_geometry_callback() */ +#define RTREE_QUERY 0x47 /* G: New-style sqlite3_rtree_query_callback() */ + /* ** An rtree structure node. */ struct RtreeNode { - RtreeNode *pParent; /* Parent node */ - i64 iNode; - int nRef; - int isDirty; - u8 *zData; - RtreeNode *pNext; /* Next node in this hash chain */ + RtreeNode *pParent; /* Parent node */ + i64 iNode; /* The node number */ + int nRef; /* Number of references to this node */ + int isDirty; /* True if the node needs to be written to disk */ + u8 *zData; /* Content of the node, as should be on disk */ + RtreeNode *pNext; /* Next node in this hash collision chain */ }; + +/* Return the number of cells in a node */ #define NCELL(pNode) readInt16(&(pNode)->zData[2]) /* -** Structure to store a deserialized rtree record. +** A single cell from a node, deserialized */ struct RtreeCell { - i64 iRowid; - RtreeCoord aCoord[RTREE_MAX_DIMENSIONS*2]; + i64 iRowid; /* Node or entry ID */ + RtreeCoord aCoord[RTREE_MAX_DIMENSIONS*2]; /* Bounding box coordinates */ +}; + + +/* +** This object becomes the sqlite3_user_data() for the SQL functions +** that are created by sqlite3_rtree_geometry_callback() and +** sqlite3_rtree_query_callback() and which appear on the right of MATCH +** operators in order to constrain a search. +** +** xGeom and xQueryFunc are the callback functions. Exactly one of +** xGeom and xQueryFunc fields is non-NULL, depending on whether the +** SQL function was created using sqlite3_rtree_geometry_callback() or +** sqlite3_rtree_query_callback(). +** +** This object is deleted automatically by the destructor mechanism in +** sqlite3_create_function_v2(). +*/ +struct RtreeGeomCallback { + int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*); + int (*xQueryFunc)(sqlite3_rtree_query_info*); + void (*xDestructor)(void*); + void *pContext; }; @@ -142500,29 +144987,16 @@ struct RtreeCell { #define RTREE_GEOMETRY_MAGIC 0x891245AB /* -** An instance of this structure must be supplied as a blob argument to -** the right-hand-side of an SQL MATCH operator used to constrain an -** r-tree query. +** An instance of this structure (in the form of a BLOB) is returned by +** the SQL functions that sqlite3_rtree_geometry_callback() and +** sqlite3_rtree_query_callback() create, and is read as the right-hand +** operand to the MATCH operator of an R-Tree. */ struct RtreeMatchArg { - u32 magic; /* Always RTREE_GEOMETRY_MAGIC */ - int (*xGeom)(sqlite3_rtree_geometry *, int, RtreeDValue*, int *); - void *pContext; - int nParam; - RtreeDValue aParam[1]; -}; - -/* -** When a geometry callback is created (see sqlite3_rtree_geometry_callback), -** a single instance of the following structure is allocated. It is used -** as the context for the user-function created by by s_r_g_c(). The object -** is eventually deleted by the destructor mechanism provided by -** sqlite3_create_function_v2() (which is called by s_r_g_c() to create -** the geometry callback function). -*/ -struct RtreeGeomCallback { - int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*); - void *pContext; + u32 magic; /* Always RTREE_GEOMETRY_MAGIC */ + RtreeGeomCallback cb; /* Info about the callback functions */ + int nParam; /* Number of parameters to the SQL function */ + RtreeDValue aParam[1]; /* Values for parameters to the SQL function */ }; #ifndef MAX @@ -142616,10 +145090,7 @@ static void nodeZero(Rtree *pRtree, RtreeNode *p){ ** in the Rtree.aHash table. */ static int nodeHash(i64 iNode){ - return ( - (iNode>>56) ^ (iNode>>48) ^ (iNode>>40) ^ (iNode>>32) ^ - (iNode>>24) ^ (iNode>>16) ^ (iNode>> 8) ^ (iNode>> 0) - ) % HASHSIZE; + return iNode % HASHSIZE; } /* @@ -142679,8 +145150,7 @@ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){ /* ** Obtain a reference to an r-tree node. */ -static int -nodeAcquire( +static int nodeAcquire( Rtree *pRtree, /* R-tree structure */ i64 iNode, /* Node number to load */ RtreeNode *pParent, /* Either the parent node or NULL */ @@ -142769,10 +145239,10 @@ nodeAcquire( ** Overwrite cell iCell of node pNode with the contents of pCell. */ static void nodeOverwriteCell( - Rtree *pRtree, - RtreeNode *pNode, - RtreeCell *pCell, - int iCell + Rtree *pRtree, /* The overall R-Tree */ + RtreeNode *pNode, /* The node into which the cell is to be written */ + RtreeCell *pCell, /* The cell to write */ + int iCell /* Index into pNode into which pCell is written */ ){ int ii; u8 *p = &pNode->zData[4 + pRtree->nBytesPerCell*iCell]; @@ -142784,7 +145254,7 @@ static void nodeOverwriteCell( } /* -** Remove cell the cell with index iCell from node pNode. +** Remove the cell with index iCell from node pNode. */ static void nodeDeleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell){ u8 *pDst = &pNode->zData[4 + pRtree->nBytesPerCell*iCell]; @@ -142801,11 +145271,10 @@ static void nodeDeleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell){ ** ** If there is not enough free space in pNode, return SQLITE_FULL. */ -static int -nodeInsertCell( - Rtree *pRtree, - RtreeNode *pNode, - RtreeCell *pCell +static int nodeInsertCell( + Rtree *pRtree, /* The overall R-Tree */ + RtreeNode *pNode, /* Write new cell into this node */ + RtreeCell *pCell /* The cell to be inserted */ ){ int nCell; /* Current number of cells in pNode */ int nMaxCell; /* Maximum number of cells for pNode */ @@ -142826,8 +145295,7 @@ nodeInsertCell( /* ** If the node is dirty, write it out to the database. */ -static int -nodeWrite(Rtree *pRtree, RtreeNode *pNode){ +static int nodeWrite(Rtree *pRtree, RtreeNode *pNode){ int rc = SQLITE_OK; if( pNode->isDirty ){ sqlite3_stmt *p = pRtree->pWriteNode; @@ -142852,8 +145320,7 @@ nodeWrite(Rtree *pRtree, RtreeNode *pNode){ ** Release a reference to a node. If the node is dirty and the reference ** count drops to zero, the node data is written to the database. */ -static int -nodeRelease(Rtree *pRtree, RtreeNode *pNode){ +static int nodeRelease(Rtree *pRtree, RtreeNode *pNode){ int rc = SQLITE_OK; if( pNode ){ assert( pNode->nRef>0 ); @@ -142881,9 +145348,9 @@ nodeRelease(Rtree *pRtree, RtreeNode *pNode){ ** an internal node, then the 64-bit integer is a child page number. */ static i64 nodeGetRowid( - Rtree *pRtree, - RtreeNode *pNode, - int iCell + Rtree *pRtree, /* The overall R-Tree */ + RtreeNode *pNode, /* The node from which to extract the ID */ + int iCell /* The cell index from which to extract the ID */ ){ assert( iCellzData[4 + pRtree->nBytesPerCell*iCell]); @@ -142893,11 +145360,11 @@ static i64 nodeGetRowid( ** Return coordinate iCoord from cell iCell in node pNode. */ static void nodeGetCoord( - Rtree *pRtree, - RtreeNode *pNode, - int iCell, - int iCoord, - RtreeCoord *pCoord /* Space to write result to */ + Rtree *pRtree, /* The overall R-Tree */ + RtreeNode *pNode, /* The node from which to extract a coordinate */ + int iCell, /* The index of the cell within the node */ + int iCoord, /* Which coordinate to extract */ + RtreeCoord *pCoord /* OUT: Space to write result to */ ){ readCoord(&pNode->zData[12 + pRtree->nBytesPerCell*iCell + 4*iCoord], pCoord); } @@ -142907,15 +145374,20 @@ static void nodeGetCoord( ** to by pCell with the results. */ static void nodeGetCell( - Rtree *pRtree, - RtreeNode *pNode, - int iCell, - RtreeCell *pCell + Rtree *pRtree, /* The overall R-Tree */ + RtreeNode *pNode, /* The node containing the cell to be read */ + int iCell, /* Index of the cell within the node */ + RtreeCell *pCell /* OUT: Write the cell contents here */ ){ - int ii; + u8 *pData; + u8 *pEnd; + RtreeCoord *pCoord; pCell->iRowid = nodeGetRowid(pRtree, pNode, iCell); - for(ii=0; iinDim*2; ii++){ - nodeGetCoord(pRtree, pNode, iCell, ii, &pCell->aCoord[ii]); + pData = pNode->zData + (12 + pRtree->nBytesPerCell*iCell); + pEnd = pData + pRtree->nDim*8; + pCoord = pCell->aCoord; + for(; pDataaConstraint ){ int i; /* Used to iterate through constraint array */ for(i=0; inConstraint; i++){ - sqlite3_rtree_geometry *pGeom = pCsr->aConstraint[i].pGeom; - if( pGeom ){ - if( pGeom->xDelUser ) pGeom->xDelUser(pGeom->pUser); - sqlite3_free(pGeom); + sqlite3_rtree_query_info *pInfo = pCsr->aConstraint[i].pInfo; + if( pInfo ){ + if( pInfo->xDelUser ) pInfo->xDelUser(pInfo->pUser); + sqlite3_free(pInfo); } } sqlite3_free(pCsr->aConstraint); @@ -143057,12 +145529,13 @@ static void freeCursorConstraints(RtreeCursor *pCsr){ */ static int rtreeClose(sqlite3_vtab_cursor *cur){ Rtree *pRtree = (Rtree *)(cur->pVtab); - int rc; + int ii; RtreeCursor *pCsr = (RtreeCursor *)cur; freeCursorConstraints(pCsr); - rc = nodeRelease(pRtree, pCsr->pNode); + sqlite3_free(pCsr->aPoint); + for(ii=0; iiaNode[ii]); sqlite3_free(pCsr); - return rc; + return SQLITE_OK; } /* @@ -143073,196 +145546,166 @@ static int rtreeClose(sqlite3_vtab_cursor *cur){ */ static int rtreeEof(sqlite3_vtab_cursor *cur){ RtreeCursor *pCsr = (RtreeCursor *)cur; - return (pCsr->pNode==0); + return pCsr->atEOF; } /* -** The r-tree constraint passed as the second argument to this function is -** guaranteed to be a MATCH constraint. -*/ -static int testRtreeGeom( - Rtree *pRtree, /* R-Tree object */ - RtreeConstraint *pConstraint, /* MATCH constraint to test */ - RtreeCell *pCell, /* Cell to test */ - int *pbRes /* OUT: Test result */ -){ - int i; - RtreeDValue aCoord[RTREE_MAX_DIMENSIONS*2]; - int nCoord = pRtree->nDim*2; - - assert( pConstraint->op==RTREE_MATCH ); - assert( pConstraint->pGeom ); - - for(i=0; iaCoord[i]); - } - return pConstraint->xGeom(pConstraint->pGeom, nCoord, aCoord, pbRes); -} - -/* -** Cursor pCursor currently points to a cell in a non-leaf page. -** Set *pbEof to true if the sub-tree headed by the cell is filtered -** (excluded) by the constraints in the pCursor->aConstraint[] -** array, or false otherwise. +** Convert raw bits from the on-disk RTree record into a coordinate value. +** The on-disk format is big-endian and needs to be converted for little- +** endian platforms. The on-disk record stores integer coordinates if +** eInt is true and it stores 32-bit floating point records if eInt is +** false. a[] is the four bytes of the on-disk record to be decoded. +** Store the results in "r". ** -** Return SQLITE_OK if successful or an SQLite error code if an error -** occurs within a geometry callback. +** There are three versions of this macro, one each for little-endian and +** big-endian processors and a third generic implementation. The endian- +** specific implementations are much faster and are preferred if the +** processor endianness is known at compile-time. The SQLITE_BYTEORDER +** macro is part of sqliteInt.h and hence the endian-specific +** implementation will only be used if this module is compiled as part +** of the amalgamation. */ -static int testRtreeCell(Rtree *pRtree, RtreeCursor *pCursor, int *pbEof){ - RtreeCell cell; - int ii; - int bRes = 0; - int rc = SQLITE_OK; - - nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell); - for(ii=0; bRes==0 && iinConstraint; ii++){ - RtreeConstraint *p = &pCursor->aConstraint[ii]; - RtreeDValue cell_min = DCOORD(cell.aCoord[(p->iCoord>>1)*2]); - RtreeDValue cell_max = DCOORD(cell.aCoord[(p->iCoord>>1)*2+1]); - - assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE - || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH - ); - - switch( p->op ){ - case RTREE_LE: case RTREE_LT: - bRes = p->rValuerValue>cell_max; - break; - - case RTREE_EQ: - bRes = (p->rValue>cell_max || p->rValueop==RTREE_MATCH ); - rc = testRtreeGeom(pRtree, p, &cell, &bRes); - bRes = !bRes; - break; - } - } - } - - *pbEof = bRes; - return rc; +#if defined(SQLITE_BYTEORDER) && SQLITE_BYTEORDER==1234 +#define RTREE_DECODE_COORD(eInt, a, r) { \ + RtreeCoord c; /* Coordinate decoded */ \ + memcpy(&c.u,a,4); \ + c.u = ((c.u>>24)&0xff)|((c.u>>8)&0xff00)| \ + ((c.u&0xff)<<24)|((c.u&0xff00)<<8); \ + r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ } - -/* -** Test if the cell that cursor pCursor currently points to -** would be filtered (excluded) by the constraints in the -** pCursor->aConstraint[] array. If so, set *pbEof to true before -** returning. If the cell is not filtered (excluded) by the constraints, -** set pbEof to zero. -** -** Return SQLITE_OK if successful or an SQLite error code if an error -** occurs within a geometry callback. -** -** This function assumes that the cell is part of a leaf node. -*/ -static int testRtreeEntry(Rtree *pRtree, RtreeCursor *pCursor, int *pbEof){ - RtreeCell cell; - int ii; - *pbEof = 0; - - nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell); - for(ii=0; iinConstraint; ii++){ - RtreeConstraint *p = &pCursor->aConstraint[ii]; - RtreeDValue coord = DCOORD(cell.aCoord[p->iCoord]); - int res; - assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE - || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH - ); - switch( p->op ){ - case RTREE_LE: res = (coord<=p->rValue); break; - case RTREE_LT: res = (coordrValue); break; - case RTREE_GE: res = (coord>=p->rValue); break; - case RTREE_GT: res = (coord>p->rValue); break; - case RTREE_EQ: res = (coord==p->rValue); break; - default: { - int rc; - assert( p->op==RTREE_MATCH ); - rc = testRtreeGeom(pRtree, p, &cell, &res); - if( rc!=SQLITE_OK ){ - return rc; - } - break; - } - } - - if( !res ){ - *pbEof = 1; - return SQLITE_OK; - } - } - - return SQLITE_OK; +#elif defined(SQLITE_BYTEORDER) && SQLITE_BYTEORDER==4321 +#define RTREE_DECODE_COORD(eInt, a, r) { \ + RtreeCoord c; /* Coordinate decoded */ \ + memcpy(&c.u,a,4); \ + r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ } +#else +#define RTREE_DECODE_COORD(eInt, a, r) { \ + RtreeCoord c; /* Coordinate decoded */ \ + c.u = ((u32)a[0]<<24) + ((u32)a[1]<<16) \ + +((u32)a[2]<<8) + a[3]; \ + r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ +} +#endif /* -** Cursor pCursor currently points at a node that heads a sub-tree of -** height iHeight (if iHeight==0, then the node is a leaf). Descend -** to point to the left-most cell of the sub-tree that matches the -** configured constraints. +** Check the RTree node or entry given by pCellData and p against the MATCH +** constraint pConstraint. */ -static int descendToCell( - Rtree *pRtree, - RtreeCursor *pCursor, - int iHeight, - int *pEof /* OUT: Set to true if cannot descend */ +static int rtreeCallbackConstraint( + RtreeConstraint *pConstraint, /* The constraint to test */ + int eInt, /* True if RTree holding integer coordinates */ + u8 *pCellData, /* Raw cell content */ + RtreeSearchPoint *pSearch, /* Container of this cell */ + sqlite3_rtree_dbl *prScore, /* OUT: score for the cell */ + int *peWithin /* OUT: visibility of the cell */ ){ - int isEof; - int rc; - int ii; - RtreeNode *pChild; - sqlite3_int64 iRowid; + int i; /* Loop counter */ + sqlite3_rtree_query_info *pInfo = pConstraint->pInfo; /* Callback info */ + int nCoord = pInfo->nCoord; /* No. of coordinates */ + int rc; /* Callback return code */ + sqlite3_rtree_dbl aCoord[RTREE_MAX_DIMENSIONS*2]; /* Decoded coordinates */ - RtreeNode *pSavedNode = pCursor->pNode; - int iSavedCell = pCursor->iCell; + assert( pConstraint->op==RTREE_MATCH || pConstraint->op==RTREE_QUERY ); + assert( nCoord==2 || nCoord==4 || nCoord==6 || nCoord==8 || nCoord==10 ); - assert( iHeight>=0 ); - - if( iHeight==0 ){ - rc = testRtreeEntry(pRtree, pCursor, &isEof); + if( pConstraint->op==RTREE_QUERY && pSearch->iLevel==1 ){ + pInfo->iRowid = readInt64(pCellData); + } + pCellData += 8; + for(i=0; iop==RTREE_MATCH ){ + rc = pConstraint->u.xGeom((sqlite3_rtree_geometry*)pInfo, + nCoord, aCoord, &i); + if( i==0 ) *peWithin = NOT_WITHIN; + *prScore = RTREE_ZERO; }else{ - rc = testRtreeCell(pRtree, pCursor, &isEof); - } - if( rc!=SQLITE_OK || isEof || iHeight==0 ){ - goto descend_to_cell_out; - } - - iRowid = nodeGetRowid(pRtree, pCursor->pNode, pCursor->iCell); - rc = nodeAcquire(pRtree, iRowid, pCursor->pNode, &pChild); - if( rc!=SQLITE_OK ){ - goto descend_to_cell_out; - } - - nodeRelease(pRtree, pCursor->pNode); - pCursor->pNode = pChild; - isEof = 1; - for(ii=0; isEof && iiiCell = ii; - rc = descendToCell(pRtree, pCursor, iHeight-1, &isEof); - if( rc!=SQLITE_OK ){ - goto descend_to_cell_out; + pInfo->aCoord = aCoord; + pInfo->iLevel = pSearch->iLevel - 1; + pInfo->rScore = pInfo->rParentScore = pSearch->rScore; + pInfo->eWithin = pInfo->eParentWithin = pSearch->eWithin; + rc = pConstraint->u.xQueryFunc(pInfo); + if( pInfo->eWithin<*peWithin ) *peWithin = pInfo->eWithin; + if( pInfo->rScore<*prScore || *prScorerScore; } } - - if( isEof ){ - assert( pCursor->pNode==pChild ); - nodeReference(pSavedNode); - nodeRelease(pRtree, pChild); - pCursor->pNode = pSavedNode; - pCursor->iCell = iSavedCell; - } - -descend_to_cell_out: - *pEof = isEof; return rc; } +/* +** Check the internal RTree node given by pCellData against constraint p. +** If this constraint cannot be satisfied by any child within the node, +** set *peWithin to NOT_WITHIN. +*/ +static void rtreeNonleafConstraint( + RtreeConstraint *p, /* The constraint to test */ + int eInt, /* True if RTree holds integer coordinates */ + u8 *pCellData, /* Raw cell content as appears on disk */ + int *peWithin /* Adjust downward, as appropriate */ +){ + sqlite3_rtree_dbl val; /* Coordinate value convert to a double */ + + /* p->iCoord might point to either a lower or upper bound coordinate + ** in a coordinate pair. But make pCellData point to the lower bound. + */ + pCellData += 8 + 4*(p->iCoord&0xfe); + + assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE + || p->op==RTREE_GT || p->op==RTREE_EQ ); + switch( p->op ){ + case RTREE_LE: + case RTREE_LT: + case RTREE_EQ: + RTREE_DECODE_COORD(eInt, pCellData, val); + /* val now holds the lower bound of the coordinate pair */ + if( p->u.rValue>=val ) return; + if( p->op!=RTREE_EQ ) break; /* RTREE_LE and RTREE_LT end here */ + /* Fall through for the RTREE_EQ case */ + + default: /* RTREE_GT or RTREE_GE, or fallthrough of RTREE_EQ */ + pCellData += 4; + RTREE_DECODE_COORD(eInt, pCellData, val); + /* val now holds the upper bound of the coordinate pair */ + if( p->u.rValue<=val ) return; + } + *peWithin = NOT_WITHIN; +} + +/* +** Check the leaf RTree cell given by pCellData against constraint p. +** If this constraint is not satisfied, set *peWithin to NOT_WITHIN. +** If the constraint is satisfied, leave *peWithin unchanged. +** +** The constraint is of the form: xN op $val +** +** The op is given by p->op. The xN is p->iCoord-th coordinate in +** pCellData. $val is given by p->u.rValue. +*/ +static void rtreeLeafConstraint( + RtreeConstraint *p, /* The constraint to test */ + int eInt, /* True if RTree holds integer coordinates */ + u8 *pCellData, /* Raw cell content as appears on disk */ + int *peWithin /* Adjust downward, as appropriate */ +){ + RtreeDValue xN; /* Coordinate value converted to a double */ + + assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE + || p->op==RTREE_GT || p->op==RTREE_EQ ); + pCellData += 8 + p->iCoord*4; + RTREE_DECODE_COORD(eInt, pCellData, xN); + switch( p->op ){ + case RTREE_LE: if( xN <= p->u.rValue ) return; break; + case RTREE_LT: if( xN < p->u.rValue ) return; break; + case RTREE_GE: if( xN >= p->u.rValue ) return; break; + case RTREE_GT: if( xN > p->u.rValue ) return; break; + default: if( xN == p->u.rValue ) return; break; + } + *peWithin = NOT_WITHIN; +} + /* ** One of the cells in node pNode is guaranteed to have a 64-bit ** integer value equal to iRowid. Return the index of this cell. @@ -143275,6 +145718,7 @@ static int nodeRowidIndex( ){ int ii; int nCell = NCELL(pNode); + assert( nCell<200 ); for(ii=0; iirScorerScore ) return -1; + if( pA->rScore>pB->rScore ) return +1; + if( pA->iLeveliLevel ) return -1; + if( pA->iLevel>pB->iLevel ) return +1; + return 0; +} + +/* +** Interchange to search points in a cursor. +*/ +static void rtreeSearchPointSwap(RtreeCursor *p, int i, int j){ + RtreeSearchPoint t = p->aPoint[i]; + assert( iaPoint[i] = p->aPoint[j]; + p->aPoint[j] = t; + i++; j++; + if( i=RTREE_CACHE_SZ ){ + nodeRelease(RTREE_OF_CURSOR(p), p->aNode[i]); + p->aNode[i] = 0; + }else{ + RtreeNode *pTemp = p->aNode[i]; + p->aNode[i] = p->aNode[j]; + p->aNode[j] = pTemp; + } + } +} + +/* +** Return the search point with the lowest current score. +*/ +static RtreeSearchPoint *rtreeSearchPointFirst(RtreeCursor *pCur){ + return pCur->bPoint ? &pCur->sPoint : pCur->nPoint ? pCur->aPoint : 0; +} + +/* +** Get the RtreeNode for the search point with the lowest score. +*/ +static RtreeNode *rtreeNodeOfFirstSearchPoint(RtreeCursor *pCur, int *pRC){ + sqlite3_int64 id; + int ii = 1 - pCur->bPoint; + assert( ii==0 || ii==1 ); + assert( pCur->bPoint || pCur->nPoint ); + if( pCur->aNode[ii]==0 ){ + assert( pRC!=0 ); + id = ii ? pCur->aPoint[0].id : pCur->sPoint.id; + *pRC = nodeAcquire(RTREE_OF_CURSOR(pCur), id, 0, &pCur->aNode[ii]); + } + return pCur->aNode[ii]; +} + +/* +** Push a new element onto the priority queue +*/ +static RtreeSearchPoint *rtreeEnqueue( + RtreeCursor *pCur, /* The cursor */ + RtreeDValue rScore, /* Score for the new search point */ + u8 iLevel /* Level for the new search point */ +){ + int i, j; + RtreeSearchPoint *pNew; + if( pCur->nPoint>=pCur->nPointAlloc ){ + int nNew = pCur->nPointAlloc*2 + 8; + pNew = sqlite3_realloc(pCur->aPoint, nNew*sizeof(pCur->aPoint[0])); + if( pNew==0 ) return 0; + pCur->aPoint = pNew; + pCur->nPointAlloc = nNew; + } + i = pCur->nPoint++; + pNew = pCur->aPoint + i; + pNew->rScore = rScore; + pNew->iLevel = iLevel; + assert( iLevel>=0 && iLevel<=RTREE_MAX_DEPTH ); + while( i>0 ){ + RtreeSearchPoint *pParent; + j = (i-1)/2; + pParent = pCur->aPoint + j; + if( rtreeSearchPointCompare(pNew, pParent)>=0 ) break; + rtreeSearchPointSwap(pCur, j, i); + i = j; + pNew = pParent; + } + return pNew; +} + +/* +** Allocate a new RtreeSearchPoint and return a pointer to it. Return +** NULL if malloc fails. +*/ +static RtreeSearchPoint *rtreeSearchPointNew( + RtreeCursor *pCur, /* The cursor */ + RtreeDValue rScore, /* Score for the new search point */ + u8 iLevel /* Level for the new search point */ +){ + RtreeSearchPoint *pNew, *pFirst; + pFirst = rtreeSearchPointFirst(pCur); + pCur->anQueue[iLevel]++; + if( pFirst==0 + || pFirst->rScore>rScore + || (pFirst->rScore==rScore && pFirst->iLevel>iLevel) + ){ + if( pCur->bPoint ){ + int ii; + pNew = rtreeEnqueue(pCur, rScore, iLevel); + if( pNew==0 ) return 0; + ii = (int)(pNew - pCur->aPoint) + 1; + if( iiaNode[ii]==0 ); + pCur->aNode[ii] = pCur->aNode[0]; + }else{ + nodeRelease(RTREE_OF_CURSOR(pCur), pCur->aNode[0]); + } + pCur->aNode[0] = 0; + *pNew = pCur->sPoint; + } + pCur->sPoint.rScore = rScore; + pCur->sPoint.iLevel = iLevel; + pCur->bPoint = 1; + return &pCur->sPoint; + }else{ + return rtreeEnqueue(pCur, rScore, iLevel); + } +} + +#if 0 +/* Tracing routines for the RtreeSearchPoint queue */ +static void tracePoint(RtreeSearchPoint *p, int idx, RtreeCursor *pCur){ + if( idx<0 ){ printf(" s"); }else{ printf("%2d", idx); } + printf(" %d.%05lld.%02d %g %d", + p->iLevel, p->id, p->iCell, p->rScore, p->eWithin + ); + idx++; + if( idxaNode[idx]); + }else{ + printf("\n"); + } +} +static void traceQueue(RtreeCursor *pCur, const char *zPrefix){ + int ii; + printf("=== %9s ", zPrefix); + if( pCur->bPoint ){ + tracePoint(&pCur->sPoint, -1, pCur); + } + for(ii=0; iinPoint; ii++){ + if( ii>0 || pCur->bPoint ) printf(" "); + tracePoint(&pCur->aPoint[ii], ii, pCur); + } +} +# define RTREE_QUEUE_TRACE(A,B) traceQueue(A,B) +#else +# define RTREE_QUEUE_TRACE(A,B) /* no-op */ +#endif + +/* Remove the search point with the lowest current score. +*/ +static void rtreeSearchPointPop(RtreeCursor *p){ + int i, j, k, n; + i = 1 - p->bPoint; + assert( i==0 || i==1 ); + if( p->aNode[i] ){ + nodeRelease(RTREE_OF_CURSOR(p), p->aNode[i]); + p->aNode[i] = 0; + } + if( p->bPoint ){ + p->anQueue[p->sPoint.iLevel]--; + p->bPoint = 0; + }else if( p->nPoint ){ + p->anQueue[p->aPoint[0].iLevel]--; + n = --p->nPoint; + p->aPoint[0] = p->aPoint[n]; + if( naNode[1] = p->aNode[n+1]; + p->aNode[n+1] = 0; + } + i = 0; + while( (j = i*2+1)aPoint[k], &p->aPoint[j])<0 ){ + if( rtreeSearchPointCompare(&p->aPoint[k], &p->aPoint[i])<0 ){ + rtreeSearchPointSwap(p, i, k); + i = k; + }else{ + break; + } + }else{ + if( rtreeSearchPointCompare(&p->aPoint[j], &p->aPoint[i])<0 ){ + rtreeSearchPointSwap(p, i, j); + i = j; + }else{ + break; + } + } + } + } +} + + +/* +** Continue the search on cursor pCur until the front of the queue +** contains an entry suitable for returning as a result-set row, +** or until the RtreeSearchPoint queue is empty, indicating that the +** query has completed. +*/ +static int rtreeStepToLeaf(RtreeCursor *pCur){ + RtreeSearchPoint *p; + Rtree *pRtree = RTREE_OF_CURSOR(pCur); + RtreeNode *pNode; + int eWithin; + int rc = SQLITE_OK; + int nCell; + int nConstraint = pCur->nConstraint; + int ii; + int eInt; + RtreeSearchPoint x; + + eInt = pRtree->eCoordType==RTREE_COORD_INT32; + while( (p = rtreeSearchPointFirst(pCur))!=0 && p->iLevel>0 ){ + pNode = rtreeNodeOfFirstSearchPoint(pCur, &rc); + if( rc ) return rc; + nCell = NCELL(pNode); + assert( nCell<200 ); + while( p->iCellzData + (4+pRtree->nBytesPerCell*p->iCell); + eWithin = FULLY_WITHIN; + for(ii=0; iiaConstraint + ii; + if( pConstraint->op>=RTREE_MATCH ){ + rc = rtreeCallbackConstraint(pConstraint, eInt, pCellData, p, + &rScore, &eWithin); + if( rc ) return rc; + }else if( p->iLevel==1 ){ + rtreeLeafConstraint(pConstraint, eInt, pCellData, &eWithin); + }else{ + rtreeNonleafConstraint(pConstraint, eInt, pCellData, &eWithin); + } + if( eWithin==NOT_WITHIN ) break; + } + p->iCell++; + if( eWithin==NOT_WITHIN ) continue; + x.iLevel = p->iLevel - 1; + if( x.iLevel ){ + x.id = readInt64(pCellData); + x.iCell = 0; + }else{ + x.id = p->id; + x.iCell = p->iCell - 1; + } + if( p->iCell>=nCell ){ + RTREE_QUEUE_TRACE(pCur, "POP-S:"); + rtreeSearchPointPop(pCur); + } + if( rScoreeWithin = eWithin; + p->id = x.id; + p->iCell = x.iCell; + RTREE_QUEUE_TRACE(pCur, "PUSH-S:"); + break; + } + if( p->iCell>=nCell ){ + RTREE_QUEUE_TRACE(pCur, "POP-Se:"); + rtreeSearchPointPop(pCur); + } + } + pCur->atEOF = p==0; + return SQLITE_OK; +} + /* ** Rtree virtual table module xNext method. */ static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){ - Rtree *pRtree = (Rtree *)(pVtabCursor->pVtab); RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; int rc = SQLITE_OK; - /* RtreeCursor.pNode must not be NULL. If is is NULL, then this cursor is - ** already at EOF. It is against the rules to call the xNext() method of - ** a cursor that has already reached EOF. - */ - assert( pCsr->pNode ); - - if( pCsr->iStrategy==1 ){ - /* This "scan" is a direct lookup by rowid. There is no next entry. */ - nodeRelease(pRtree, pCsr->pNode); - pCsr->pNode = 0; - }else{ - /* Move to the next entry that matches the configured constraints. */ - int iHeight = 0; - while( pCsr->pNode ){ - RtreeNode *pNode = pCsr->pNode; - int nCell = NCELL(pNode); - for(pCsr->iCell++; pCsr->iCelliCell++){ - int isEof; - rc = descendToCell(pRtree, pCsr, iHeight, &isEof); - if( rc!=SQLITE_OK || !isEof ){ - return rc; - } - } - pCsr->pNode = pNode->pParent; - rc = nodeParentIndex(pRtree, pNode, &pCsr->iCell); - if( rc!=SQLITE_OK ){ - return rc; - } - nodeReference(pCsr->pNode); - nodeRelease(pRtree, pNode); - iHeight++; - } - } - + /* Move to the next entry that matches the configured constraints. */ + RTREE_QUEUE_TRACE(pCsr, "POP-Nx:"); + rtreeSearchPointPop(pCsr); + rc = rtreeStepToLeaf(pCsr); return rc; } @@ -143346,13 +146044,14 @@ static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){ ** Rtree virtual table module xRowid method. */ static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){ - Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; - - assert(pCsr->pNode); - *pRowid = nodeGetRowid(pRtree, pCsr->pNode, pCsr->iCell); - - return SQLITE_OK; + RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); + int rc = SQLITE_OK; + RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); + if( rc==SQLITE_OK && p ){ + *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell); + } + return rc; } /* @@ -143361,13 +146060,18 @@ static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ Rtree *pRtree = (Rtree *)cur->pVtab; RtreeCursor *pCsr = (RtreeCursor *)cur; + RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); + RtreeCoord c; + int rc = SQLITE_OK; + RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); + if( rc ) return rc; + if( p==0 ) return SQLITE_OK; if( i==0 ){ - i64 iRowid = nodeGetRowid(pRtree, pCsr->pNode, pCsr->iCell); - sqlite3_result_int64(ctx, iRowid); + sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell)); }else{ - RtreeCoord c; - nodeGetCoord(pRtree, pCsr->pNode, pCsr->iCell, i-1, &c); + if( rc ) return rc; + nodeGetCoord(pRtree, pNode, p->iCell, i-1, &c); #ifndef SQLITE_RTREE_INT_ONLY if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ sqlite3_result_double(ctx, c.f); @@ -143378,7 +146082,6 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ sqlite3_result_int(ctx, c.i); } } - return SQLITE_OK; } @@ -143389,12 +146092,18 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ ** *ppLeaf to 0 and return SQLITE_OK. If an error occurs, set *ppLeaf ** to zero and return an SQLite error code. */ -static int findLeafNode(Rtree *pRtree, i64 iRowid, RtreeNode **ppLeaf){ +static int findLeafNode( + Rtree *pRtree, /* RTree to search */ + i64 iRowid, /* The rowid searching for */ + RtreeNode **ppLeaf, /* Write the node here */ + sqlite3_int64 *piNode /* Write the node-id here */ +){ int rc; *ppLeaf = 0; sqlite3_bind_int64(pRtree->pReadRowid, 1, iRowid); if( sqlite3_step(pRtree->pReadRowid)==SQLITE_ROW ){ i64 iNode = sqlite3_column_int64(pRtree->pReadRowid, 0); + if( piNode ) *piNode = iNode; rc = nodeAcquire(pRtree, iNode, 0, ppLeaf); sqlite3_reset(pRtree->pReadRowid); }else{ @@ -143410,9 +146119,10 @@ static int findLeafNode(Rtree *pRtree, i64 iRowid, RtreeNode **ppLeaf){ ** operator. */ static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){ - RtreeMatchArg *p; - sqlite3_rtree_geometry *pGeom; - int nBlob; + RtreeMatchArg *pBlob; /* BLOB returned by geometry function */ + sqlite3_rtree_query_info *pInfo; /* Callback information */ + int nBlob; /* Size of the geometry function blob */ + int nExpected; /* Expected size of the BLOB */ /* Check that value is actually a blob. */ if( sqlite3_value_type(pValue)!=SQLITE_BLOB ) return SQLITE_ERROR; @@ -143425,27 +146135,29 @@ static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){ return SQLITE_ERROR; } - pGeom = (sqlite3_rtree_geometry *)sqlite3_malloc( - sizeof(sqlite3_rtree_geometry) + nBlob - ); - if( !pGeom ) return SQLITE_NOMEM; - memset(pGeom, 0, sizeof(sqlite3_rtree_geometry)); - p = (RtreeMatchArg *)&pGeom[1]; + pInfo = (sqlite3_rtree_query_info*)sqlite3_malloc( sizeof(*pInfo)+nBlob ); + if( !pInfo ) return SQLITE_NOMEM; + memset(pInfo, 0, sizeof(*pInfo)); + pBlob = (RtreeMatchArg*)&pInfo[1]; - memcpy(p, sqlite3_value_blob(pValue), nBlob); - if( p->magic!=RTREE_GEOMETRY_MAGIC - || nBlob!=(int)(sizeof(RtreeMatchArg) + (p->nParam-1)*sizeof(RtreeDValue)) - ){ - sqlite3_free(pGeom); + memcpy(pBlob, sqlite3_value_blob(pValue), nBlob); + nExpected = (int)(sizeof(RtreeMatchArg) + + (pBlob->nParam-1)*sizeof(RtreeDValue)); + if( pBlob->magic!=RTREE_GEOMETRY_MAGIC || nBlob!=nExpected ){ + sqlite3_free(pInfo); return SQLITE_ERROR; } + pInfo->pContext = pBlob->cb.pContext; + pInfo->nParam = pBlob->nParam; + pInfo->aParam = pBlob->aParam; - pGeom->pContext = p->pContext; - pGeom->nParam = p->nParam; - pGeom->aParam = p->aParam; - - pCons->xGeom = p->xGeom; - pCons->pGeom = pGeom; + if( pBlob->cb.xGeom ){ + pCons->u.xGeom = pBlob->cb.xGeom; + }else{ + pCons->op = RTREE_QUERY; + pCons->u.xQueryFunc = pBlob->cb.xQueryFunc; + } + pCons->pInfo = pInfo; return SQLITE_OK; } @@ -143459,44 +146171,59 @@ static int rtreeFilter( ){ Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; - RtreeNode *pRoot = 0; int ii; int rc = SQLITE_OK; + int iCell = 0; rtreeReference(pRtree); + /* Reset the cursor to the same state as rtreeOpen() leaves it in. */ freeCursorConstraints(pCsr); - pCsr->iStrategy = idxNum; + sqlite3_free(pCsr->aPoint); + memset(pCsr, 0, sizeof(RtreeCursor)); + pCsr->base.pVtab = (sqlite3_vtab*)pRtree; + pCsr->iStrategy = idxNum; if( idxNum==1 ){ /* Special case - lookup by rowid. */ RtreeNode *pLeaf; /* Leaf on which the required cell resides */ + RtreeSearchPoint *p; /* Search point for the the leaf */ i64 iRowid = sqlite3_value_int64(argv[0]); - rc = findLeafNode(pRtree, iRowid, &pLeaf); - pCsr->pNode = pLeaf; - if( pLeaf ){ - assert( rc==SQLITE_OK ); - rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &pCsr->iCell); + i64 iNode = 0; + rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode); + if( rc==SQLITE_OK && pLeaf!=0 ){ + p = rtreeSearchPointNew(pCsr, RTREE_ZERO, 0); + assert( p!=0 ); /* Always returns pCsr->sPoint */ + pCsr->aNode[0] = pLeaf; + p->id = iNode; + p->eWithin = PARTLY_WITHIN; + rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell); + p->iCell = iCell; + RTREE_QUEUE_TRACE(pCsr, "PUSH-F1:"); + }else{ + pCsr->atEOF = 1; } }else{ /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array ** with the configured constraints. */ - if( argc>0 ){ + rc = nodeAcquire(pRtree, 1, 0, &pRoot); + if( rc==SQLITE_OK && argc>0 ){ pCsr->aConstraint = sqlite3_malloc(sizeof(RtreeConstraint)*argc); pCsr->nConstraint = argc; if( !pCsr->aConstraint ){ rc = SQLITE_NOMEM; }else{ memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*argc); + memset(pCsr->anQueue, 0, sizeof(u32)*(pRtree->iDepth + 1)); assert( (idxStr==0 && argc==0) || (idxStr && (int)strlen(idxStr)==argc*2) ); for(ii=0; iiaConstraint[ii]; p->op = idxStr[ii*2]; - p->iCoord = idxStr[ii*2+1]-'a'; - if( p->op==RTREE_MATCH ){ + p->iCoord = idxStr[ii*2+1]-'0'; + if( p->op>=RTREE_MATCH ){ /* A MATCH operator. The right-hand-side must be a blob that ** can be cast into an RtreeMatchArg object. One created using ** an sqlite3_rtree_geometry_callback() SQL user function. @@ -143505,41 +146232,35 @@ static int rtreeFilter( if( rc!=SQLITE_OK ){ break; } + p->pInfo->nCoord = pRtree->nDim*2; + p->pInfo->anQueue = pCsr->anQueue; + p->pInfo->mxLevel = pRtree->iDepth + 1; }else{ #ifdef SQLITE_RTREE_INT_ONLY - p->rValue = sqlite3_value_int64(argv[ii]); + p->u.rValue = sqlite3_value_int64(argv[ii]); #else - p->rValue = sqlite3_value_double(argv[ii]); + p->u.rValue = sqlite3_value_double(argv[ii]); #endif } } } } - if( rc==SQLITE_OK ){ - pCsr->pNode = 0; - rc = nodeAcquire(pRtree, 1, 0, &pRoot); - } - if( rc==SQLITE_OK ){ - int isEof = 1; - int nCell = NCELL(pRoot); - pCsr->pNode = pRoot; - for(pCsr->iCell=0; rc==SQLITE_OK && pCsr->iCelliCell++){ - assert( pCsr->pNode==pRoot ); - rc = descendToCell(pRtree, pCsr, pRtree->iDepth, &isEof); - if( !isEof ){ - break; - } - } - if( rc==SQLITE_OK && isEof ){ - assert( pCsr->pNode==pRoot ); - nodeRelease(pRtree, pRoot); - pCsr->pNode = 0; - } - assert( rc!=SQLITE_OK || !pCsr->pNode || pCsr->iCellpNode) ); + RtreeSearchPoint *pNew; + pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, pRtree->iDepth+1); + if( pNew==0 ) return SQLITE_NOMEM; + pNew->id = 1; + pNew->iCell = 0; + pNew->eWithin = PARTLY_WITHIN; + assert( pCsr->bPoint==1 ); + pCsr->aNode[0] = pRoot; + pRoot = 0; + RTREE_QUEUE_TRACE(pCsr, "PUSH-Fm:"); + rc = rtreeStepToLeaf(pCsr); } } + nodeRelease(pRtree, pRoot); rtreeRelease(pRtree); return rc; } @@ -143641,7 +146362,7 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ break; } zIdxStr[iIdx++] = op; - zIdxStr[iIdx++] = p->iColumn - 1 + 'a'; + zIdxStr[iIdx++] = p->iColumn - 1 + '0'; pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2); pIdxInfo->aConstraintUsage[ii].omit = 1; } @@ -143734,62 +146455,32 @@ static RtreeDValue cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){ return (cellArea(pRtree, &cell)-area); } -#if VARIANT_RSTARTREE_CHOOSESUBTREE || VARIANT_RSTARTREE_SPLIT static RtreeDValue cellOverlap( Rtree *pRtree, RtreeCell *p, RtreeCell *aCell, - int nCell, - int iExclude + int nCell ){ int ii; - RtreeDValue overlap = 0.0; + RtreeDValue overlap = RTREE_ZERO; for(ii=0; iinDim*2); jj+=2){ - RtreeDValue x1, x2; - - x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj])); - x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1])); - - if( x2nDim*2); jj+=2){ + RtreeDValue x1, x2; + x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj])); + x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1])); + if( x2iDepth-1) ){ - int jj; - aCell = sqlite3_malloc(sizeof(RtreeCell)*nCell); - if( !aCell ){ - rc = SQLITE_NOMEM; - nodeRelease(pRtree, pNode); - pNode = 0; - continue; - } - for(jj=0; jjiDepth-1) ){ - overlap = cellOverlapEnlargement(pRtree,&cell,pCell,aCell,nCell,iCell); - }else{ - overlap = 0.0; - } - if( (iCell==0) - || (overlapnDim; i++){ - RtreeDValue x1 = DCOORD(aCell[0].aCoord[i*2]); - RtreeDValue x2 = DCOORD(aCell[0].aCoord[i*2+1]); - RtreeDValue x3 = x1; - RtreeDValue x4 = x2; - int jj; - - int iCellLeft = 0; - int iCellRight = 0; - - for(jj=1; jjx4 ) x4 = right; - if( left>x3 ){ - x3 = left; - iCellRight = jj; - } - if( rightmaxNormalInnerWidth ){ - iLeftSeed = iCellLeft; - iRightSeed = iCellRight; - } - } - } - - *piLeftSeed = iLeftSeed; - *piRightSeed = iRightSeed; -} -#endif /* VARIANT_GUTTMAN_LINEAR_SPLIT */ - -#if VARIANT_GUTTMAN_QUADRATIC_SPLIT -/* -** Implementation of the quadratic variant of the PickNext() function from -** Guttman[84]. -*/ -static RtreeCell *QuadraticPickNext( - Rtree *pRtree, - RtreeCell *aCell, - int nCell, - RtreeCell *pLeftBox, - RtreeCell *pRightBox, - int *aiUsed -){ - #define FABS(a) ((a)<0.0?-1.0*(a):(a)) - - int iSelect = -1; - RtreeDValue fDiff; - int ii; - for(ii=0; iifDiff ){ - fDiff = diff; - iSelect = ii; - } - } - } - aiUsed[iSelect] = 1; - return &aCell[iSelect]; -} - -/* -** Implementation of the quadratic variant of the PickSeeds() function from -** Guttman[84]. -*/ -static void QuadraticPickSeeds( - Rtree *pRtree, - RtreeCell *aCell, - int nCell, - int *piLeftSeed, - int *piRightSeed -){ - int ii; - int jj; - - int iLeftSeed = 0; - int iRightSeed = 1; - RtreeDValue fWaste = 0.0; - - for(ii=0; iifWaste ){ - iLeftSeed = ii; - iRightSeed = jj; - fWaste = waste; - } - } - } - - *piLeftSeed = iLeftSeed; - *piRightSeed = iRightSeed; -} -#endif /* VARIANT_GUTTMAN_QUADRATIC_SPLIT */ /* ** Arguments aIdx, aDistance and aSpare all point to arrays of size @@ -144230,7 +146735,6 @@ static void SortByDimension( } } -#if VARIANT_RSTARTREE_SPLIT /* ** Implementation of the R*-tree variant of SplitNode from Beckman[1990]. */ @@ -144249,7 +146753,7 @@ static int splitNodeStartree( int iBestDim = 0; int iBestSplit = 0; - RtreeDValue fBestMargin = 0.0; + RtreeDValue fBestMargin = RTREE_ZERO; int nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int)); @@ -144270,9 +146774,9 @@ static int splitNodeStartree( } for(ii=0; iinDim; ii++){ - RtreeDValue margin = 0.0; - RtreeDValue fBestOverlap = 0.0; - RtreeDValue fBestArea = 0.0; + RtreeDValue margin = RTREE_ZERO; + RtreeDValue fBestOverlap = RTREE_ZERO; + RtreeDValue fBestArea = RTREE_ZERO; int iBestLeft = 0; int nLeft; @@ -144298,7 +146802,7 @@ static int splitNodeStartree( } margin += cellMargin(pRtree, &left); margin += cellMargin(pRtree, &right); - overlap = cellOverlap(pRtree, &left, &right, 1, -1); + overlap = cellOverlap(pRtree, &left, &right, 1); area = cellArea(pRtree, &left) + cellArea(pRtree, &right); if( (nLeft==RTREE_MINCELLS(pRtree)) || (overlap0; i--){ - RtreeCell *pNext; - pNext = PickNext(pRtree, aCell, nCell, pBboxLeft, pBboxRight, aiUsed); - RtreeDValue diff = - cellGrowth(pRtree, pBboxLeft, pNext) - - cellGrowth(pRtree, pBboxRight, pNext) - ; - if( (RTREE_MINCELLS(pRtree)-NCELL(pRight)==i) - || (diff>0.0 && (RTREE_MINCELLS(pRtree)-NCELL(pLeft)!=i)) - ){ - nodeInsertCell(pRtree, pRight, pNext); - cellUnion(pRtree, pBboxRight, pNext); - }else{ - nodeInsertCell(pRtree, pLeft, pNext); - cellUnion(pRtree, pBboxLeft, pNext); - } - } - - sqlite3_free(aiUsed); - return SQLITE_OK; -} -#endif static int updateMapping( Rtree *pRtree, @@ -144464,7 +146912,8 @@ static int SplitNode( memset(pLeft->zData, 0, pRtree->iNodeSize); memset(pRight->zData, 0, pRtree->iNodeSize); - rc = AssignCells(pRtree, aCell, nCell, pLeft, pRight, &leftbbox, &rightbbox); + rc = splitNodeStartree(pRtree, aCell, nCell, pLeft, pRight, + &leftbbox, &rightbbox); if( rc!=SQLITE_OK ){ goto splitnode_out; } @@ -144747,7 +147196,7 @@ static int Reinsert( } for(ii=0; iinDim; iDim++){ RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) - DCOORD(aCell[ii].aCoord[iDim*2])); @@ -144813,16 +147262,12 @@ static int rtreeInsertCell( } } if( nodeInsertCell(pRtree, pNode, pCell) ){ -#if VARIANT_RSTARTREE_REINSERT if( iHeight<=pRtree->iReinsertHeight || pNode->iNode==1){ rc = SplitNode(pRtree, pNode, pCell, iHeight); }else{ pRtree->iReinsertHeight = iHeight; rc = Reinsert(pRtree, pNode, pCell, iHeight); } -#else - rc = SplitNode(pRtree, pNode, pCell, iHeight); -#endif }else{ rc = AdjustTree(pRtree, pNode, pCell); if( rc==SQLITE_OK ){ @@ -144892,7 +147337,7 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){ ** about to be deleted. */ if( rc==SQLITE_OK ){ - rc = findLeafNode(pRtree, iDelete, &pLeaf); + rc = findLeafNode(pRtree, iDelete, &pLeaf, 0); } /* Delete the cell in question from the leaf node. */ @@ -145137,26 +147582,32 @@ static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){ ** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST. */ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){ - const char *zSql = "SELECT stat FROM sqlite_stat1 WHERE tbl= ? || '_rowid'"; + const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'"; + char *zSql; sqlite3_stmt *p; int rc; i64 nRow = 0; - rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_text(p, 1, pRtree->zName, -1, SQLITE_STATIC); - if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0); - rc = sqlite3_finalize(p); - }else if( rc!=SQLITE_NOMEM ){ - rc = SQLITE_OK; - } - - if( rc==SQLITE_OK ){ - if( nRow==0 ){ - pRtree->nRowEst = RTREE_DEFAULT_ROWEST; - }else{ - pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST); + zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName); + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0); + if( rc==SQLITE_OK ){ + if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0); + rc = sqlite3_finalize(p); + }else if( rc!=SQLITE_NOMEM ){ + rc = SQLITE_OK; } + + if( rc==SQLITE_OK ){ + if( nRow==0 ){ + pRtree->nRowEst = RTREE_DEFAULT_ROWEST; + }else{ + pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST); + } + } + sqlite3_free(zSql); } return rc; @@ -145223,7 +147674,8 @@ static int rtreeSqlInit( char *zCreate = sqlite3_mprintf( "CREATE TABLE \"%w\".\"%w_node\"(nodeno INTEGER PRIMARY KEY, data BLOB);" "CREATE TABLE \"%w\".\"%w_rowid\"(rowid INTEGER PRIMARY KEY, nodeno INTEGER);" -"CREATE TABLE \"%w\".\"%w_parent\"(nodeno INTEGER PRIMARY KEY, parentnode INTEGER);" +"CREATE TABLE \"%w\".\"%w_parent\"(nodeno INTEGER PRIMARY KEY," + " parentnode INTEGER);" "INSERT INTO '%q'.'%q_node' VALUES(1, zeroblob(%d))", zDb, zPrefix, zDb, zPrefix, zDb, zPrefix, zDb, zPrefix, pRtree->iNodeSize ); @@ -145425,6 +147877,8 @@ static int rtreeInit( if( rc==SQLITE_OK ){ *ppVtab = (sqlite3_vtab *)pRtree; }else{ + assert( *ppVtab==0 ); + assert( pRtree->nBusy==1 ); rtreeRelease(pRtree); } return rc; @@ -145435,10 +147889,10 @@ static int rtreeInit( ** Implementation of a scalar function that decodes r-tree nodes to ** human readable strings. This can be used for debugging and analysis. ** -** The scalar function takes two arguments, a blob of data containing -** an r-tree node, and the number of dimensions the r-tree indexes. -** For a two-dimensional r-tree structure called "rt", to deserialize -** all nodes, a statement like: +** The scalar function takes two arguments: (1) the number of dimensions +** to the rtree (between 1 and 5, inclusive) and (2) a blob of data containing +** an r-tree node. For a two-dimensional r-tree structure called "rt", to +** deserialize all nodes, a statement like: ** ** SELECT rtreenode(2, data) FROM rt_node; ** @@ -145471,7 +147925,7 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){ nCell = (int)strlen(zCell); for(jj=0; jjxDestructor ) pInfo->xDestructor(pInfo->pContext); sqlite3_free(p); } /* -** Each call to sqlite3_rtree_geometry_callback() creates an ordinary SQLite -** scalar user function. This C function is the callback used for all such -** registered SQL functions. +** Each call to sqlite3_rtree_geometry_callback() or +** sqlite3_rtree_query_callback() creates an ordinary SQLite +** scalar function that is implemented by this routine. ** -** The scalar user functions return a blob that is interpreted by r-tree -** table MATCH operators. +** All this function does is construct an RtreeMatchArg object that +** contains the geometry-checking callback routines and a list of +** parameters to this function, then return that RtreeMatchArg object +** as a BLOB. +** +** The R-Tree MATCH operator will read the returned BLOB, deserialize +** the RtreeMatchArg object, and use the RtreeMatchArg object to figure +** out which elements of the R-Tree should be returned by the query. */ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){ RtreeGeomCallback *pGeomCtx = (RtreeGeomCallback *)sqlite3_user_data(ctx); @@ -145563,8 +148035,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){ }else{ int i; pBlob->magic = RTREE_GEOMETRY_MAGIC; - pBlob->xGeom = pGeomCtx->xGeom; - pBlob->pContext = pGeomCtx->pContext; + pBlob->cb = pGeomCtx[0]; pBlob->nParam = nArg; for(i=0; iaParam[i] = sqlite3_value_double(aArg[i]); #endif } - sqlite3_result_blob(ctx, pBlob, nBlob, doSqlite3Free); + sqlite3_result_blob(ctx, pBlob, nBlob, sqlite3_free); } } @@ -145581,10 +148052,10 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){ ** Register a new geometry function for use with the r-tree MATCH operator. */ SQLITE_API int sqlite3_rtree_geometry_callback( - sqlite3 *db, - const char *zGeom, - int (*xGeom)(sqlite3_rtree_geometry *, int, RtreeDValue *, int *), - void *pContext + sqlite3 *db, /* Register SQL function on this connection */ + const char *zGeom, /* Name of the new SQL function */ + int (*xGeom)(sqlite3_rtree_geometry*,int,RtreeDValue*,int*), /* Callback */ + void *pContext /* Extra data associated with the callback */ ){ RtreeGeomCallback *pGeomCtx; /* Context object for new user-function */ @@ -145592,12 +148063,36 @@ SQLITE_API int sqlite3_rtree_geometry_callback( pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback)); if( !pGeomCtx ) return SQLITE_NOMEM; pGeomCtx->xGeom = xGeom; + pGeomCtx->xQueryFunc = 0; + pGeomCtx->xDestructor = 0; pGeomCtx->pContext = pContext; - - /* Create the new user-function. Register a destructor function to delete - ** the context object when it is no longer required. */ return sqlite3_create_function_v2(db, zGeom, -1, SQLITE_ANY, - (void *)pGeomCtx, geomCallback, 0, 0, doSqlite3Free + (void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback + ); +} + +/* +** Register a new 2nd-generation geometry function for use with the +** r-tree MATCH operator. +*/ +SQLITE_API int sqlite3_rtree_query_callback( + sqlite3 *db, /* Register SQL function on this connection */ + const char *zQueryFunc, /* Name of new SQL function */ + int (*xQueryFunc)(sqlite3_rtree_query_info*), /* Callback */ + void *pContext, /* Extra data passed into the callback */ + void (*xDestructor)(void*) /* Destructor for the extra data */ +){ + RtreeGeomCallback *pGeomCtx; /* Context object for new user-function */ + + /* Allocate and populate the context object. */ + pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback)); + if( !pGeomCtx ) return SQLITE_NOMEM; + pGeomCtx->xGeom = 0; + pGeomCtx->xQueryFunc = xQueryFunc; + pGeomCtx->xDestructor = xDestructor; + pGeomCtx->pContext = pContext; + return sqlite3_create_function_v2(db, zQueryFunc, -1, SQLITE_ANY, + (void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback ); } diff --git a/TMessagesProj/jni/sqlite/sqlite3.h b/TMessagesProj/jni/sqlite/sqlite3.h index 1f19ada4..9879f80d 100644 --- a/TMessagesProj/jni/sqlite/sqlite3.h +++ b/TMessagesProj/jni/sqlite/sqlite3.h @@ -107,9 +107,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.8.4.1" -#define SQLITE_VERSION_NUMBER 3008004 -#define SQLITE_SOURCE_ID "2014-03-11 15:27:36 018d317b1257ce68a92908b05c9c7cf1494050d0" +#define SQLITE_VERSION "3.8.6" +#define SQLITE_VERSION_NUMBER 3008006 +#define SQLITE_SOURCE_ID "2014-08-15 11:46:33 9491ba7d738528f168657adb43a198238abde19e" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -269,7 +269,7 @@ typedef sqlite_uint64 sqlite3_uint64; ** ** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors ** for the [sqlite3] object. -** ^Calls to sqlite3_close() and sqlite3_close_v2() return SQLITE_OK if +** ^Calls to sqlite3_close() and sqlite3_close_v2() return [SQLITE_OK] if ** the [sqlite3] object is successfully destroyed and all associated ** resources are deallocated. ** @@ -277,7 +277,7 @@ typedef sqlite_uint64 sqlite3_uint64; ** statements or unfinished sqlite3_backup objects then sqlite3_close() ** will leave the database connection open and return [SQLITE_BUSY]. ** ^If sqlite3_close_v2() is called with unfinalized prepared statements -** and unfinished sqlite3_backups, then the database connection becomes +** and/or unfinished sqlite3_backups, then the database connection becomes ** an unusable "zombie" which will automatically be deallocated when the ** last prepared statement is finalized or the last sqlite3_backup is ** finished. The sqlite3_close_v2() interface is intended for use with @@ -290,7 +290,7 @@ typedef sqlite_uint64 sqlite3_uint64; ** with the [sqlite3] object prior to attempting to close the object. ^If ** sqlite3_close_v2() is called on a [database connection] that still has ** outstanding [prepared statements], [BLOB handles], and/or -** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation +** [sqlite3_backup] objects then it returns [SQLITE_OK] and the deallocation ** of resources is deferred until all [prepared statements], [BLOB handles], ** and [sqlite3_backup] objects are also destroyed. ** @@ -386,16 +386,14 @@ SQLITE_API int sqlite3_exec( /* ** CAPI3REF: Result Codes -** KEYWORDS: SQLITE_OK {error code} {error codes} -** KEYWORDS: {result code} {result codes} +** KEYWORDS: {result code definitions} ** ** Many SQLite functions return an integer result code from the set shown ** here in order to indicate success or failure. ** ** New error codes may be added in future versions of SQLite. ** -** See also: [SQLITE_IOERR_READ | extended result codes], -** [sqlite3_vtab_on_conflict()] [SQLITE_ROLLBACK | result codes]. +** See also: [extended result code definitions] */ #define SQLITE_OK 0 /* Successful result */ /* beginning-of-error-codes */ @@ -433,26 +431,19 @@ SQLITE_API int sqlite3_exec( /* ** CAPI3REF: Extended Result Codes -** KEYWORDS: {extended error code} {extended error codes} -** KEYWORDS: {extended result code} {extended result codes} +** KEYWORDS: {extended result code definitions} ** -** In its default configuration, SQLite API routines return one of 26 integer -** [SQLITE_OK | result codes]. However, experience has shown that many of +** In its default configuration, SQLite API routines return one of 30 integer +** [result codes]. However, experience has shown that many of ** these result codes are too coarse-grained. They do not provide as ** much information about problems as programmers might like. In an effort to ** address this, newer versions of SQLite (version 3.3.8 and later) include ** support for additional result codes that provide more detailed information -** about errors. The extended result codes are enabled or disabled +** about errors. These [extended result codes] are enabled or disabled ** on a per database connection basis using the -** [sqlite3_extended_result_codes()] API. -** -** Some of the available extended result codes are listed here. -** One may expect the number of extended result codes will increase -** over time. Software that uses extended result codes should expect -** to see new result codes in future releases of SQLite. -** -** The SQLITE_OK result code will never be extended. It will always -** be exactly zero. +** [sqlite3_extended_result_codes()] API. Or, the extended code for +** the most recent error can be obtained using +** [sqlite3_extended_errcode()]. */ #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) #define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) @@ -560,7 +551,10 @@ SQLITE_API int sqlite3_exec( ** file that were written at the application level might have changed ** and that adjacent bytes, even bytes within the same sector are ** guaranteed to be unchanged. The SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN -** flag indicate that a file cannot be deleted when open. +** flag indicate that a file cannot be deleted when open. The +** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on +** read-only media and cannot be changed even by processes with +** elevated privileges. */ #define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC512 0x00000002 @@ -575,6 +569,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOCAP_SEQUENTIAL 0x00000400 #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800 #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 +#define SQLITE_IOCAP_IMMUTABLE 0x00002000 /* ** CAPI3REF: File Locking Levels @@ -681,7 +676,7 @@ struct sqlite3_file { ** locking strategy (for example to use dot-file locks), to inquire ** about the status of a lock, or to break stale locks. The SQLite ** core reserves all opcodes less than 100 for its own use. -** A [SQLITE_FCNTL_LOCKSTATE | list of opcodes] less than 100 is available. +** A [file control opcodes | list of opcodes] less than 100 is available. ** Applications that define a custom xFileControl method should use opcodes ** greater than 100 to avoid conflicts. VFS implementations should ** return [SQLITE_NOTFOUND] for file control opcodes that they do not @@ -754,6 +749,7 @@ struct sqlite3_io_methods { /* ** CAPI3REF: Standard File Control Opcodes +** KEYWORDS: {file control opcodes} {file control opcode} ** ** These integer constants are opcodes for the xFileControl method ** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()] @@ -943,6 +939,12 @@ struct sqlite3_io_methods { ** on whether or not the file has been renamed, moved, or deleted since it ** was first opened. ** +**
  • [[SQLITE_FCNTL_WIN32_SET_HANDLE]] +** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This +** opcode causes the xFileControl method to swap the file handle with the one +** pointed to by the pArg argument. This capability is used during testing +** and only needs to be supported when SQLITE_TEST is defined. +** ** */ #define SQLITE_FCNTL_LOCKSTATE 1 @@ -966,6 +968,7 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_HAS_MOVED 20 #define SQLITE_FCNTL_SYNC 21 #define SQLITE_FCNTL_COMMIT_PHASETWO 22 +#define SQLITE_FCNTL_WIN32_SET_HANDLE 23 /* ** CAPI3REF: Mutex Handle @@ -2026,27 +2029,33 @@ SQLITE_API int sqlite3_complete16(const void *sql); /* ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors ** -** ^This routine sets a callback function that might be invoked whenever -** an attempt is made to open a database table that another thread -** or process has locked. +** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X +** that might be invoked with argument P whenever +** an attempt is made to access a database table associated with +** [database connection] D when another thread +** or process has the table locked. +** The sqlite3_busy_handler() interface is used to implement +** [sqlite3_busy_timeout()] and [PRAGMA busy_timeout]. ** -** ^If the busy callback is NULL, then [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED] +** ^If the busy callback is NULL, then [SQLITE_BUSY] ** is returned immediately upon encountering the lock. ^If the busy callback ** is not NULL, then the callback might be invoked with two arguments. ** ** ^The first argument to the busy handler is a copy of the void* pointer which ** is the third argument to sqlite3_busy_handler(). ^The second argument to ** the busy handler callback is the number of times that the busy handler has -** been invoked for this locking event. ^If the +** been invoked for the same locking event. ^If the ** busy callback returns 0, then no additional attempts are made to -** access the database and [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED] is returned. +** access the database and [SQLITE_BUSY] is returned +** to the application. ** ^If the callback returns non-zero, then another attempt -** is made to open the database for reading and the cycle repeats. +** is made to access the database and the cycle repeats. ** ** The presence of a busy handler does not guarantee that it will be invoked ** when there is lock contention. ^If SQLite determines that invoking the busy ** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY] -** or [SQLITE_IOERR_BLOCKED] instead of invoking the busy handler. +** to the application instead of invoking the +** busy handler. ** Consider a scenario where one process is holding a read lock that ** it is trying to promote to a reserved lock and ** a second process is holding a reserved lock that it is trying @@ -2060,28 +2069,15 @@ SQLITE_API int sqlite3_complete16(const void *sql); ** ** ^The default busy callback is NULL. ** -** ^The [SQLITE_BUSY] error is converted to [SQLITE_IOERR_BLOCKED] -** when SQLite is in the middle of a large transaction where all the -** changes will not fit into the in-memory cache. SQLite will -** already hold a RESERVED lock on the database file, but it needs -** to promote this lock to EXCLUSIVE so that it can spill cache -** pages into the database file without harm to concurrent -** readers. ^If it is unable to promote the lock, then the in-memory -** cache will be left in an inconsistent state and so the error -** code is promoted from the relatively benign [SQLITE_BUSY] to -** the more severe [SQLITE_IOERR_BLOCKED]. ^This error code promotion -** forces an automatic rollback of the changes. See the -** -** CorruptionFollowingBusyError wiki page for a discussion of why -** this is important. -** ** ^(There can only be a single busy handler defined for each ** [database connection]. Setting a new busy handler clears any ** previously set handler.)^ ^Note that calling [sqlite3_busy_timeout()] -** will also set or clear the busy handler. +** or evaluating [PRAGMA busy_timeout=N] will change the +** busy handler and thus clear any previously set busy handler. ** ** The busy callback should not take any actions which modify the -** database connection that invoked the busy handler. Any such actions +** database connection that invoked the busy handler. In other words, +** the busy handler is not reentrant. Any such actions ** result in undefined behavior. ** ** A busy handler must not close the database connection @@ -2097,7 +2093,7 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); ** will sleep multiple times until at least "ms" milliseconds of sleeping ** have accumulated. ^After at least "ms" milliseconds of sleeping, ** the handler returns 0 which causes [sqlite3_step()] to return -** [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED]. +** [SQLITE_BUSY]. ** ** ^Calling this routine with an argument less than or equal to zero ** turns off all busy handlers. @@ -2106,6 +2102,8 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); ** [database connection] any any given moment. If another busy handler ** was defined (using [sqlite3_busy_handler()]) prior to calling ** this routine, that other busy handler is cleared.)^ +** +** See also: [PRAGMA busy_timeout] */ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); @@ -2507,8 +2505,8 @@ SQLITE_API int sqlite3_set_authorizer( ** [sqlite3_set_authorizer | authorizer documentation] for additional ** information. ** -** Note that SQLITE_IGNORE is also used as a [SQLITE_ROLLBACK | return code] -** from the [sqlite3_vtab_on_conflict()] interface. +** Note that SQLITE_IGNORE is also used as a [conflict resolution mode] +** returned from the [sqlite3_vtab_on_conflict()] interface. */ #define SQLITE_DENY 1 /* Abort the SQL statement with an error */ #define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ @@ -2779,6 +2777,30 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** ^If sqlite3_open_v2() is used and the "cache" parameter is present in ** a URI filename, its value overrides any behavior requested by setting ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. +** +**
  • psow: ^The psow parameter may be "true" (or "on" or "yes" or +** "1") or "false" (or "off" or "no" or "0") to indicate that the +** [powersafe overwrite] property does or does not apply to the +** storage media on which the database file resides. ^The psow query +** parameter only works for the built-in unix and Windows VFSes. +** +**
  • nolock: ^The nolock parameter is a boolean query parameter +** which if set disables file locking in rollback journal modes. This +** is useful for accessing a database on a filesystem that does not +** support locking. Caution: Database corruption might result if two +** or more processes write to the same database and any one of those +** processes uses nolock=1. +** +**
  • immutable: ^The immutable parameter is a boolean query +** parameter that indicates that the database file is stored on +** read-only media. ^When immutable is set, SQLite assumes that the +** database file cannot be changed, even by a process with higher +** privilege, and so the database is opened read-only and all locking +** and change detection is disabled. Caution: Setting the immutable +** property on a database file that does in fact change can result +** in incorrect query results and/or [SQLITE_CORRUPT] errors. +** See also: [SQLITE_IOCAP_IMMUTABLE]. +** ** ** ** ^Specifying an unknown parameter in the query component of a URI is not an @@ -2808,8 +2830,9 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** Open file "data.db" in the current directory for read-only access. ** Regardless of whether or not shared-cache mode is enabled by ** default, use a private cache. -** file:/home/fred/data.db?vfs=unix-nolock -** Open file "/home/fred/data.db". Use the special VFS "unix-nolock". +** file:/home/fred/data.db?vfs=unix-dotfile +** Open file "/home/fred/data.db". Use the special VFS "unix-dotfile" +** that uses dot-files in place of posix advisory locking. ** file:data.db?mode=readonly ** An error. "readonly" is not a valid option for the "mode" parameter. ** @@ -4670,6 +4693,13 @@ SQLITE_API int sqlite3_sleep(int); ** is a NULL pointer, then SQLite performs a search for an appropriate ** temporary file directory. ** +** Applications are strongly discouraged from using this global variable. +** It is required to set a temporary folder on Windows Runtime (WinRT). +** But for all other platforms, it is highly recommended that applications +** neither read nor write this variable. This global variable is a relic +** that exists for backwards compatibility of legacy applications and should +** be avoided in new projects. +** ** It is not safe to read or modify this variable in more than one ** thread at a time. It is not safe to read or modify this variable ** if a [database connection] is being used at the same time in a separate @@ -4688,6 +4718,11 @@ SQLITE_API int sqlite3_sleep(int); ** Hence, if this variable is modified directly, either it should be ** made NULL or made to point to memory obtained from [sqlite3_malloc] ** or else the use of the [temp_store_directory pragma] should be avoided. +** Except when requested by the [temp_store_directory pragma], SQLite +** does not free the memory that sqlite3_temp_directory points to. If +** the application wants that memory to be freed, it must do +** so itself, taking care to only do so after all [database connection] +** objects have been destroyed. ** ** Note to Windows Runtime users: The temporary directory must be set ** prior to calling [sqlite3_open] or [sqlite3_open_v2]. Otherwise, various @@ -5822,10 +5857,12 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*); **
  • SQLITE_MUTEX_RECURSIVE **
  • SQLITE_MUTEX_STATIC_MASTER **
  • SQLITE_MUTEX_STATIC_MEM -**
  • SQLITE_MUTEX_STATIC_MEM2 +**
  • SQLITE_MUTEX_STATIC_OPEN **
  • SQLITE_MUTEX_STATIC_PRNG **
  • SQLITE_MUTEX_STATIC_LRU -**
  • SQLITE_MUTEX_STATIC_LRU2 +**
  • SQLITE_MUTEX_STATIC_PMEM +**
  • SQLITE_MUTEX_STATIC_APP1 +**
  • SQLITE_MUTEX_STATIC_APP2 ** )^ ** ** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) @@ -6029,6 +6066,9 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*); #define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */ #define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */ #define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */ +#define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */ +#define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */ +#define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */ /* ** CAPI3REF: Retrieve the mutex for a database connection @@ -6123,7 +6163,9 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21 -#define SQLITE_TESTCTRL_LAST 21 +#define SQLITE_TESTCTRL_BYTEORDER 22 +#define SQLITE_TESTCTRL_ISINIT 23 +#define SQLITE_TESTCTRL_LAST 23 /* ** CAPI3REF: SQLite Runtime Status @@ -7107,6 +7149,9 @@ SQLITE_API void *sqlite3_wal_hook( ** ^The [wal_autocheckpoint pragma] can be used to invoke this interface ** from SQL. ** +** ^Checkpoints initiated by this mechanism are +** [sqlite3_wal_checkpoint_v2|PASSIVE]. +** ** ^Every new [database connection] defaults to having the auto-checkpoint ** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT] ** pages. The use of this interface @@ -7123,6 +7168,10 @@ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); ** empty string, then a checkpoint is run on all databases of ** connection D. ^If the database connection D is not in ** [WAL | write-ahead log mode] then this interface is a harmless no-op. +** ^The [sqlite3_wal_checkpoint(D,X)] interface initiates a +** [sqlite3_wal_checkpoint_v2|PASSIVE] checkpoint. +** Use the [sqlite3_wal_checkpoint_v2()] interface to get a FULL +** or RESET checkpoint. ** ** ^The [wal_checkpoint pragma] can be used to invoke this interface ** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the @@ -7145,10 +7194,12 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); ** Checkpoint as many frames as possible without waiting for any database ** readers or writers to finish. Sync the db file if all frames in the log ** are checkpointed. This mode is the same as calling -** sqlite3_wal_checkpoint(). The busy-handler callback is never invoked. +** sqlite3_wal_checkpoint(). The [sqlite3_busy_handler|busy-handler callback] +** is never invoked. ** **
    SQLITE_CHECKPOINT_FULL
    -** This mode blocks (calls the busy-handler callback) until there is no +** This mode blocks (it invokes the +** [sqlite3_busy_handler|busy-handler callback]) until there is no ** database writer and all readers are reading from the most recent database ** snapshot. It then checkpoints all frames in the log file and syncs the ** database file. This call blocks database writers while it is running, @@ -7156,7 +7207,8 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); ** **
    SQLITE_CHECKPOINT_RESTART
    ** This mode works the same way as SQLITE_CHECKPOINT_FULL, except after -** checkpointing the log file it blocks (calls the busy-handler callback) +** checkpointing the log file it blocks (calls the +** [sqlite3_busy_handler|busy-handler callback]) ** until all readers are reading from the database file only. This ensures ** that the next client to write to the database file restarts the log file ** from the beginning. This call blocks database writers while it is running, @@ -7294,6 +7346,7 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); /* ** CAPI3REF: Conflict resolution modes +** KEYWORDS: {conflict resolution mode} ** ** These constants are returned by [sqlite3_vtab_on_conflict()] to ** inform a [virtual table] implementation what the [ON CONFLICT] mode @@ -7346,6 +7399,16 @@ extern "C" { #endif typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry; +typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info; + +/* The double-precision datatype used by RTree depends on the +** SQLITE_RTREE_INT_ONLY compile-time option. +*/ +#ifdef SQLITE_RTREE_INT_ONLY + typedef sqlite3_int64 sqlite3_rtree_dbl; +#else + typedef double sqlite3_rtree_dbl; +#endif /* ** Register a geometry callback named zGeom that can be used as part of an @@ -7356,11 +7419,7 @@ typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry; SQLITE_API int sqlite3_rtree_geometry_callback( sqlite3 *db, const char *zGeom, -#ifdef SQLITE_RTREE_INT_ONLY - int (*xGeom)(sqlite3_rtree_geometry*, int n, sqlite3_int64 *a, int *pRes), -#else - int (*xGeom)(sqlite3_rtree_geometry*, int n, double *a, int *pRes), -#endif + int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*), void *pContext ); @@ -7372,11 +7431,60 @@ SQLITE_API int sqlite3_rtree_geometry_callback( struct sqlite3_rtree_geometry { void *pContext; /* Copy of pContext passed to s_r_g_c() */ int nParam; /* Size of array aParam[] */ - double *aParam; /* Parameters passed to SQL geom function */ + sqlite3_rtree_dbl *aParam; /* Parameters passed to SQL geom function */ void *pUser; /* Callback implementation user data */ void (*xDelUser)(void *); /* Called by SQLite to clean up pUser */ }; +/* +** Register a 2nd-generation geometry callback named zScore that can be +** used as part of an R-Tree geometry query as follows: +** +** SELECT ... FROM WHERE MATCH $zQueryFunc(... params ...) +*/ +SQLITE_API int sqlite3_rtree_query_callback( + sqlite3 *db, + const char *zQueryFunc, + int (*xQueryFunc)(sqlite3_rtree_query_info*), + void *pContext, + void (*xDestructor)(void*) +); + + +/* +** A pointer to a structure of the following type is passed as the +** argument to scored geometry callback registered using +** sqlite3_rtree_query_callback(). +** +** Note that the first 5 fields of this structure are identical to +** sqlite3_rtree_geometry. This structure is a subclass of +** sqlite3_rtree_geometry. +*/ +struct sqlite3_rtree_query_info { + void *pContext; /* pContext from when function registered */ + int nParam; /* Number of function parameters */ + sqlite3_rtree_dbl *aParam; /* value of function parameters */ + void *pUser; /* callback can use this, if desired */ + void (*xDelUser)(void*); /* function to free pUser */ + sqlite3_rtree_dbl *aCoord; /* Coordinates of node or entry to check */ + unsigned int *anQueue; /* Number of pending entries in the queue */ + int nCoord; /* Number of coordinates */ + int iLevel; /* Level of current node or entry */ + int mxLevel; /* The largest iLevel value in the tree */ + sqlite3_int64 iRowid; /* Rowid for current entry */ + sqlite3_rtree_dbl rParentScore; /* Score of parent node */ + int eParentWithin; /* Visibility of parent node */ + int eWithin; /* OUT: Visiblity */ + sqlite3_rtree_dbl rScore; /* OUT: Write the score here */ +}; + +/* +** Allowed values for sqlite3_rtree_query.eWithin and .eParentWithin. +*/ +#define NOT_WITHIN 0 /* Object completely outside of query region */ +#define PARTLY_WITHIN 1 /* Object partially overlaps query region */ +#define FULLY_WITHIN 2 /* Object fully contained within query region */ + #ifdef __cplusplus } /* end of the 'extern "C"' block */ diff --git a/TMessagesProj/libs/armeabi-v7a/libtmessages.so b/TMessagesProj/libs/armeabi-v7a/libtmessages.so index 57e76551e85a7de3d7194a15661658f7869c371a..dbd6f46f7ba7a4a0e8f3398b9c3497fd2956fb9e 100755 GIT binary patch delta 261729 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

    mFqQ<-Ks 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

    xleU?!TLllWK@A+|ww`*d{S~gZo#)u^ z-{~7)Xi)yoviF^=EcZv*mH(&gvM+ks+Uf~$0d;CM^z== zz7#W^Ka{5(2bqJR4E-RnU^T`?uF!EVamQpb*8ETDqMbkFKRr*|SEf=rYxkRFPN~9K zU!48(-a_eHJF?&PoR$`DT@b4M zO^ffXm%oLhUotII*qN99_$_^|McDmKYX?kzH!wLwM-nmeAB)41NkHgJ5D{0^0D3Q% z7xrdnL?#N!QdI8Sv_o8!jBW7T$n=!NjJN5v)^nApQ= zi0jmw0x@KMH6~rh1}2gW+H2VNRvsFdA0_&Nj)D2#E?9>d)M+ab}bE?!?tV< z@c}&S*1Ss?1BEC@NKfnXbg>g_eHk5HMbktFYtyrl`0S`V2Sc{sR&i(+yB*_DuCwFhI*?n)S!@q?YcNM{CnsWFQ!=bwJ`&6F1u zyIjqqh3jq%@*S*y4G(v1ZI4aRZQYtWtuf>E53-3t7ZSDb%&MuYwya8N@mQA9f(Vip zUdM(uUAUOnK|jSpJE^1n5Gi=qKK-$^DT>|an^nQ5B$2RWh%}jY+S;+7o%PZ-^rcYgWYY-X=ZQD-iD1-aQPz{;dVY|iJhI@e*~kI5u5M> zcBz6xro>>uS3Q~kKJV%(&zk*0x;+@R#b?Mc|DUbvbw!=;bzQITbp@R3b?Gkmy1+4~ z6bl1q{;R40bDZ%^E>hex1=@{4ol4C4hph=hY$o$dYJjTl=;p@iVZy`;22=+1%1xt! z!3xQWl|TiFN4~XsVCj!6F$j7XZ2Q?pxp$JP==*kG;krFOQ&!AM%wPR_YG_tOWi{f(>Z8Mb+-)5$rgA3vIn;9I^Ujgt#15rj+mHW9i=K=(u>p4*n zK<;A?!i3E>n+#D=vkgefhHa}t0DT&K@P9U^cX%^lPBc$N5a+ipYyg;i%5kwzSg#}I zOl5^Ai~_S6OORh*_FCgHX>RV=BQosg=1O|Qud7(vC|O%9r)V|GY@7R?jHwyf#Kk9A z=fX`g1Pte267GO{e915)i>Qiexr!;UZ^m)(onl(_#f{y&?!xF+|ltSC-# za1|T#+{Qm|`7+P4Dx|t`6}&FuN5b1GJ_E}t#Mjvz?><%lAo$^&Vu-ItqzC}y@YWjinb}*7&WiP59j0ha z^ahGGg`c3C$^rC@@S!>^_veZOD{2L4~UDk_g;8yC~J$Dm5$3*lM2)-O> z^{6s@&Y7dMrgOKv^;rIP$q(|ofXV)$*EhYo_tlJL&2|n@HyO*8 zzIqjkh%5G44{FkWr>lD|+WQ`K*VYQ6{oR(a%;p|arV0U-8`o9&2|h{o*Bo9Gd zHn5>O0;PdI@nv_OaJptG)KTm)%$G3Iip>{N1?}v~6Ig0%t!=4EE-CYtno2|0OMKp} z4#kQO7w-ii2%0|`pwwF7$&^d<7EB);ncS|CKcBI8{fCS1Lf9&I^;PjJX!a6-x0s~E zs9h<1XIho>S#}#laItnK2~upMU3bKbGs#5nZS=Q0iGq*rclv&hIPg(2KH?^nOwuQ8 zM;8RG*G1$hV@-`U-J?m8xaLt3>vxd`LKu@iZ`~TIntJM{c=SW?FJrTNr z$01-o;u6^&f5$8AJ*&{NzB%dEbj>Okb~_cK=ipt-*Ae*K1PP} z^F^OoBu;*oZWPDNf@@Cwh_8ezQvES5W_8LwL4Mz`)S2Q@7~XVm>t$efZObDuO4(;EML|yFpOpUc~DU%F@VKMH{s{MPnL?_Pv&` zHyKR7NH_akps#d_E7M44P$}fXLKf9VO^@zl-y@*^6;%{k0s~=}KnA+(XXP<#&)?wx`%j?Mgd$7>= zol6yCW|PtKZIlxi&nBTHkdGC%QOED%y4fTaqkQpq@z88Yx{c!9+2o}G^Br&B^l0Oj zc#n1I^b_{912 zh@U==!PrJqe!q-XaJF0T6v6JLQ7W&Parvw;nt$JaJ>6Fy{t$>a%Vom+_1^b}q@49YI9jTry7?3Wjw+ z63G)}tt_Qe-24QYs1I{T^}N5%vot-YjXva-gFnD8MWiL0lon@iqbtQ*PmuVaZFFIa zCpy5Vi-nk~*O^fKo+J*MM~04rfeIZp$96@!G~#~N>XczwIT0O8fFs5~8=#ksC?G%2cVk2 zM?dP6muXGOIY&Fgz}t=YHs#-=m7Sda(Fe{neFlQlQOloc!k9{s?C13DG}k3YJPBQK zvLtSOk_bcFp}ryWsBI+{`+xBF~iL zpwD8}Haf275%llAY}UJ<-Fy{M6{Plh>gH2>gh>x74(c(do)SFww*%2uT=^8ys%J|} z?7&)s-dn7Aio6<$p}1L#yS!_;DD)OuOe9hof;K3yJ-&x!TO2i?Jnp-VM&7)1lvg%b=8lIBu`zehaLoZ_klWTL_WbXf7k0unK?9mrDdC34fu2V2mc z<9oCj5A52E4*SdpMfg1e-g~@75As>x(}Jz=Rv-___A3M*?9Pu!V&Fp33tv)aj~KLw z7`0pJXLlmE?%e{cc5av;hrG6x9=YSzYUQ>vtmIc0kr8~W`0*n0=!9g1(hPJ5Jo#Er zf~!PslSB6ykgQ+dx|)lhX#FUYVa!18mX>5r1I;ORHc-*6xEd_AiX)#UkD{wjf>E+P z?=)+o&Wv_RM z1D24XbK7Z$^E4RWc#xXBOAfO0X&dP2(-xsV4#8RGRRnUA7q-)@PI>7Y5H!eRptVPt zAG4Iq)TzEgFecIT&Q?tNU!=qW2R+^;?pZr*Ag;w>as2#5V@vm zg+&9?vK+X!?es;b9RIVO9u~J9XT73yezqmsKWi&J(YkaE7e55+^;nw%uf{p{=dp=3 zxl7!!loZJBNTPNbI^$xexNsSH!@RpwQQ(D<9VRF+$+t<0QV-Aw+;R>pEJOY}Z~p82 zLpZO)6q}vVN9rcJ?AdBypCfs-yy0FJKcOtCq2bX7RVX}(+2mIl42|D;;DC!~GRbg%@78JZh0sPFMgHN8oV%2BiJB}DsX9-ub`?vH zi(|6L6`8(M49g}PWlwdA?`M-i@+~w^{5cz9N-Hhze#;J6Onq`L7FrjciYTbLh-*H8 z{|(Jq5u7f5pX%M6oci4@^trn#%g^puu@rZ}9e3}ad1|-Ah`PdXkQ?}fr10ZMw9(Gq zW5_5OUG9gF91e~fEIQgxJP(!RpHI5kODg^)%_VqH>5&hmx#BB1WU}lhNj#oIjDxn& zmOELiVk{njmOy$N!xnmt{Vw&e%+HM}EzJ&Hr31in3$TF2$QQ`)v2zO!Nb|S@Qab0~ z49AhYP0f$BCu$)uX6~BFvMB?a}OZ@#sa%?~yLbE=? zf~OTeTGg@&HcuVjLipE1mS@z_87}dQmq<`f9i50W3RdRzme>DVrVV9=;ffMh;@-%5 z`P-G{xDt#jYIe`+tkwU$ry5t(F434vLeReMUU6YAnTn&j zUU6S8nXlMFn|~LT%Sn;84nPAwx`WbAE($;ji=D#+pSGRyC`;`A=tF0zk4rqUoa}@M z-{Jf;?PYSBmpMT}D@l6X7CN-`X>{*FwwFiuMxc9tmp}wMRr&jz8etXj`=SfC&}gxA zCBl13CW|Lll7+H@u1`Z=fq)&+LJ6EiX4a~abW_fcgrXB^kK{~2LEEZ%i=k<<7Q@R48_=DcjTIDH*G&?Q=5B?4aQ(k(IUHS$>4W9_eM zxq<4UTl7^-A{Tx9ga+ZKbu`oY>AKg*zj*Rk`$Fy(E$9`EuM?x+7JA?&xYDfhs;%yA z>pQPQhaHpe0ZrBN90oY}w4@aLFd2=GhC*&lOJ2YD8)R4YcI|BtmO3*<`$<+ z72xXw6=-5e9d!i(B{p!s3J9Ea2vt;99CfQORpO*Kh>m|pT>J)k$YWD}P0DxT`Zq|- z0L{Ckk{_)V0>m-G&-5;GAIpWxq^UxO^+`wi@8aneM)7!qTInLz0k^gRQgq{*?6c1hz+X>fpDB= zNEGyNCfJ0dUVycJirTaZPom%a3Kr#Vl4fW4RTzYa+^z@;t+UzR;-EohS3e6En{QR( zhsM>f!f!XgG;GK1Q=uqlt$g}!nLVy-w%}o59SBdK1AI|80;~ImZBoZKhtAu%=*yC2 zkJoNbd#Uh{aHV;vso1oon(3Y2MN=A;tfDC8j+)I_+eOJsK%MSY;R0GzI#hka$2TsO4 zCv}WC{G{EpB2F-boCo0e*GDp%W3$fDM?1xgH%Y{kiHB6t{ETyD~F+oaHr-aNBa2#|AWn z+JGY!Nq&t?R;_mt%ahQqBhwQ$(cLh^u*Oe9xtVrt0zVcLn1kj}>p;@TKksbEoxQ+S zXC=*<9b*n(w4;kO%*$(wi5Z!I;)P7c-vD7d&2UlaeI69Cg%Q)b79v~U;wc9~dH$E6 zT5V0jD7buTxpT~vD5XK8JgH;t;iue#wDUH5^;aPtif7DV-VXX%uXxi;)&)7}jcyLR zs6L?Y$J)na+=2uw=H-!P=3P#v3HZz=xA0}_vimLK3R&KPTg-M*TJ6?pIVSrEf=K}p z6NnXE%${bzczz7!+GZ%%JemqY-8ST*Uk~SpQmA_#Ku%(%#z9s}ftHL3@hM$KxBpXL z@;475#k94G39UuXNd4TtezUE6Vb)_+F{SW&eD_u5u|F1yjSDo;`OFND5|)Zwy9W+; zgaM92Ab(fh#8MZsUz72mpXtla*&v(b)Tu%{7#IX4Yd%CHgLo^SJfxn`jZiu;g79up zvyMbW`a;K`#L(Qe1v_{@1#oiIIv?FF8s=2E_m9iE#K+c=kU_6?D@(`Ku!eXbP}LU@ z-CXP?s{%D$b1F-}gJ7%J?@{capLdD{>qww%e3$s)Ix=*ssYhABN*zNfF5Y5e2{!sl zZvW%SJ0Mo4V+f2_R;uH=VcC{-5xgb_G4L=0OGB(f9Yr1hkK?BO0$ z_4TcKsC2HclRkH@IhsVF{FUjtp;TlV-s{){+@Wb*;+pkj89zl)wa`kF){RR@luM$7rK&I&QE4@nMVL^$u^%>pH-SUU3I8cwRS`N8C ze6d0dc#8~~cbhTv*neBk**DXlTDVg$$Ediurg-nJ zXtEldu%gt_>Cg#|v2jR28HbF#cW6hKQfNlE)*+X&xceGyEmi@^54(o;a7WyE(0(!qX?vQ8PZ@oC!I-)h3)!hE31ed zb>W;fjT`d4%|owWdD^~yO?b^ZxHuRcq4{jBzL>Z4bp=-Cy1b~Ic()Mu3^1=TYs z#zTkLF0jr_C%G%1)bZh=kD8f2^)6BZu_~roiRCWs=&fiT{kN`|=h%FEGSv6mlLAl0 z37G>L5b)Obz-@k1e8uCJzZkKt`a(cw4 zv%Y=O(S4J}05i2xpL6ZU(6+KJ^a2L7Mu^GIP^^lpQ+y2wGtp-& zc^I_4u17R%C1DxzHL`d{xpjypn#xQ)?@V`_%p5)WKo~n}V)3&7U%YU)THZn?a8+%CBlYNNB4L45mz9(Q(F@U;&EV_vXswtw7r{o z&oIGRAtYxOR&55{`Hys(v?sF;IoFt12m3u4o*p+c2QhSCG5&4Rzu%8E#a-lw?xisL z{zxZ?v)?9SgodBznAs}R4-+)|QzK-SLrIu(9t!JS+TJB9wv#09+emW(Q!eQ3YPb0K zb~1=B72n)W)@!C<`m$odR}V1q^eo@H?H+tDeDJpH`=Yn<6nCa*Y?M z^9wd%p${2&5sB~^>%VEka&W3XOa))Bbx;BkZ6@v=(t8;@IXA2vuf8}-JozpOhF_hZ zQ>=TJLL1-!J>P`HAQ3~`PuzTgI#qIiJonz zJmhZX>{KK@WvEw$oJR(D*yAU4w1Sh?Aulkmz0u5$b~$I*VRnBu$*zAEiLbJLp=Y~b zHeT|T9eLSDMdKW&>!JnX!@DrFZ;2y!kz}}#cZsWakwro0;YYc`6k@Wvmw-8NE5E+QY=ZL3mHHz{=IsU42Qtk8Qdv0^tF2rhQGOZ;{>Nm4Y?pSnbE zkqi!d-U*{h@#BJzmdRofYJff?tKKDg8^{T`uC>z(U3K;}*hEs1cZrX5W+n=jDbp~2 zSbuDR>R%+W5o5cuGb@trH5UBMr4-wD-7j=Xw|Gq?V*~AUa~HdJ8cd{?DXW-seYa?^ zkd>PAROn@CCk?`{ub-#8d&OfGa$xRRnhr)Y4bOOADs5f}W0QB)NcU6OIg9izoN>Op zu}~Q4zB1F@LXYmdc2)FkJ3M_61uN4nfO8ugm#+Y_bruR<@mMh#ntm2eX43@L7A`Uc zZRvZ;0%>mZW~T>N7YuJZe46pO6s6*-@R{4?!CeeOxE+{d6kO37oy-v=8vBDLIz_sQ zL|wlCXigkkLI%j{qkSg3Z3)EgmT$BV-YhcoTQX z&(I%5&r%XT{t7HYW6-TvXbJ2H9JL{d3=gK zQw54XPmMidMkxu2+iC3cmy~ANX=sfihDo4o#>r={N#PKG_>oIi#k?q~_+BZztjATk zT#1UGWL&^r5_AQaF(3bU;8@J%kPnl?S6*72PGm; z^rhoJshISL3?)Kt^@dDV&r~TF8N6(+VK}En-wQ5wb~b8fjDY#ufb|3&l`|m8kz6zv zQ;*9-@wP5%7pIlMpXv&|*Q+;qU~xG^BXOVPUUG)qR%|5{= zNM|~03fR5DbRJ->JEcdp$uDXOe0KR4ZF%>{TLYetgzLM}F$Wq|Bg}Yd1{LHdRlX0L zoH!U_(_n-RG;q2zw<7uT(oOBZrO$?OW=M&t`RApGe#mp`(5=5Dt-*ecbNmKKq!FlO zV816En_FYw)l_f;uSma*!RM(5Ijd9NM5@sdOT&wNi@bO1cNq%%6~z_lir77W;`sjz z%>97Me&veR4N87wzg;SpUT;+?fclS`lG-yS1756F-fCViXRu(tg{9j*ozZ?tSHzYBlQ$)1yC_D}0SzJGII-`|%(cl)!yFZ=KBuMG<8 z7uIjLX18X6=AQwUfMtLCn-^gB@B1tE|MM@x|8Bp-frA4*0zV1(B)}4A4*V`q#jAK< z-dy8bbxtxhkNz&x~l$AJw-iO9iaXR2&wg+ zUwVGzxzqC{&vehpo(Y~!#72HqSyf-Es#PP&ebqn6E#+R-3RQ+`v}&vJyfkoe?Ct?} zU&{qVde4HcsNZhgZtvYb#k^U6MT&@Jfef0;H&XHukf~}LjC}Av^lB=n!pTAr(v^kO zI?_JFcT!pbx6`|%naW)n zn61s$6?z35fXX&<@sI3S*LCULVLqEzM=J%j+`u)Rp95Bk);aQc!%yLVUBL=VN#gTB zHhXw!Fu;enN0s8HgNK-W&1cUX&2pljxPiLr@dOAgCKpe&6eVm7rgl{VBC0P zfIt~0QDSzof1xF?%&Hio3oUi%j3Wg_sOL3B@FK3n+)RK!x?}dln`!mH6-U=A=ANmGjN?O)Y%b=7&{cRJw1tQoNPM4H+T4VVM9aj~~Y6 zwz4WYHej;rm(P_p6Y9J|6#$^-l2yjHk3nj?z#g=`4AUNg{UDTS>uF{HgEoOdn_7b` zpTssNO)#ZM&xPSF2Ak35F@{QGENo6u8sA=8*KFwvNYYe9%pFy3$-3?t<$N<`C1j!) zaZ|dk_#)&aE<`P!O`n2lED_ZgrE){tvTvomI)41O_znzbnbMuppMqECG#k}^z~WO# zfqS}Q(99Tr$6AXGMy?siMx9G*&&ah{EKWuAqPI9lX(~6}Qa_|cWefxQ72rBW}G)1Vw(O@xJ zQ>3TER^qHmd@M~{z(;6v4$9ie>$__K;}dwu_6D(r@ckBkm=5S)ttjJ1(*9)ESPZQy z?DbV#;Do5qx2X|Iz+ousOihDL2s$t=guBlmJPQC3F6R#x-bzbXg?buINuf5)c=w1N zRffKOtX@}u`|Lj={TMkBTfeYSOqo*boh*081}gj#VkxLMsycpbNJME&R5PCpIE)!6 zW~91*fs#S4A}&R&X}tZWWj_*=l;S^Ae6YACK|zlam!@zdV#Mj`7o;2A4z5TXj zEO7ahV!sq0z~9$R;YO;&U!z3WT2n1WzqKN=p9_f=w`VT2-op@glO9vE1*ouI zPYL6*4VG|-WtbLY{30NBV{FXgo0;*env-;e12N%hEOLIlO}pV`3qR)NSk73o$_Isk z?&3n5D`PiU^5{NA0|P>eX)X_&BmOKLGud_Rb5w={4-cM_Hm#2LRs`vRc^h{yr^ ztbQNd0tzuY!>6#!TELr~lQU+D8ZR0)H*b#?z0*w(yrVY9M2nv3^r~sXnx{axAU0hE zr+}!@%_&@MIvD<^b{@aE63blWOM6F~PurWAer^8}$reyIFm7JlmliF`E#9s4DbN+> zU}1sAtFV~FpHpcCtV6JoviXQizqlZf*u7V!?X$2Ubu(O?UzE%6{3&U>!RRs=12%$o zhCO2`kS2o`%!*A!4LHz*<^G$1cba=u@{hf~MkRieF?;&z=s>|I?;)Ew1g>CO5dOOV z0~~*7y8n`(RL zyI(oGCTkp1!EoNk|6Z3umkvU;!wWDV@q|jQEyY<1fKiGm_P}XL(Q53HQyEiZl;Z7- zQecF9=2UBeN2M?~`YNu-$~ZZE%1d0cqGR? z8ZBSsIJ)|i%(o;iB;pJ6WY?12@Uh!|uMfBW2LY8DJCIiDenw6_t%`f8J_X#Py5eRO zXNcZ=5f-ya*Jx4oE#M5AM~QQcy7r0Fi`VAnmTG2um7A6Kx30WgtIc(mqD?-9v;!7` zAzt;L;vmc0@(H?FcgeVg_*PNsZRim`E zu22oWqA;dQFNWQ`r7K)vaazg}`xfwx$=I9PYLY}$jbHnolY-a(jA}mq*#z9r^&N>4 z2wR~D+NWGYb4QN3wmr9ahvp&05Fz)A9h#>VBZW;nHU73VbIVm-AxZ@aMgZ#0!)jrU_#pz;M;@u%Ow*;^zrHSxxTdvo?40Kg|TPzH#NM_*)0C`%o@>f;KzxwyuyR z9k5UX5wlpMdCbjjKXZEef?y8ehtTlx!O!H{c5CL^)IhI_h>=tiLc%{od%~>3ZVYk| zR)}v%Y%?GiWk${W6bz5gvhv|saS8EH2o15*_B1Tqxp2fH460#Q>?Z({h7wf%_PCEAh@Z!&dgdgKNl zr`T&=86OC-WqssseQx5{P{X2|bs2dwl~#(g(;*Yje=piBL<1BV9oTBnX%%MCY+u^I6R z)AmdY5=zfu{;{Ojr?XH0h!lp~(62?Ehfw@o*r9Yyii$!E@@^dMx1dB)SZqSx)Sk6@ zy7k2^L7O9yb**>g!`xGd#4vLH$8?ru`H6jD_#9m}SGCg`?FhA=)rVTPEXy`K9t_0YcWn33qQBIFsVeu^_YN>_brtky&Kct-bmid+|2?=qbxazfX zNI-#OtbL1Uy==62G#-WIbP3u#2`vh7dIqw!-H+E5lG3q#fHwbEs2vx;OpX&X$w8$= ziC9T`tDEuITqAb)6cL7|DXfbHSJ3V&BMI2FcrD5OpQdSx_;JKj0?Xh0FRD|LbqO+M zMz=7Ag3IO0A#vJB{!=wpbE#QZ@$>RDxAaF)AuHwEwZ+tS{&8(CW)q&xhq^kM%ke)S z{j;aS8IXR>BiiYctSy@PK(}z9X|E@n{3}J*pXQJH|NuB=t!Ng1*vkAU3Yd2w0wjpCk1dkg{CEO-!%Or?nfzvPj2JhINJYc zV;nGqQ->gUHlvc@21r&dvWONHa8)w(nF546XhWmVq4w~( z*e>=}MeeC;14d)Elb}bfJCZ28jq{XWVK-)Dpk6FZ8}V=G{SmS3W1eFbq%cmh^Rtbmd>HPOZ1LU zERR_ZFG%D@sl>t*Zn)nyx*Qh;`XLoqA&QwuITKWM&q=CB*5UYWCLf+^X0^P4(TK-r z#DCvEwT-`dq%mF|iOm>^b15N6VWiPDi<8rRa_1dG2-;a>M0K&@6{FV>Ets3^10eea zDzo$XWcO<8WFH+SRmUt|0)xXI#3E2;WJ_}mW?-SG;_rMcj0d&urQL~4VfXIqmQ?&+ zvAm8nlJjhF>l(1CDDjUBI{KoOgsV;#Z#(>^rElSA>tE#cEa1|qjZxzARD%$-`4XGd zR?=^*gX6$62qFFOt_UC-_&^X;&7H!eVgmo5v+;=j=)NWFt zd-E-gdYPm&9_4>zb2@>}eW*EUERu**_vwnP)*q$4Ve|LpTR$|bYgOXtL-b84CZ^BF zvXE+Z1wKXRq3`~P9MgPrN|QN_2pBOPo3^pq<3QG2(4hD15msF>KZY}^oCd8nn-pXy z&^lOamYl|=aj^r0V=yG@ikg-!T-3by8)>iU8;XTbd^w;w?hDDp0f$nS)DOfjU#Nt3 zJkp{U-i%GKd;>HEznn1(M_9j+jv3OK$FH4ivS;ftu&-j`Nl zQsnie6jyiC?@s2dqE+3qrc1JHc^*@o`I$qkiCLwV&7SJ>KY2zw52X;mOJXXO&0Ck5 zYN@%$eNYCsu}Z8>b;+_39x=4%AtaQ}Yk|n|!KbM}q5=c?&)-&5Nmenko@FOTYe`m- z$J+ZDyNUA1x=pe6Ss;EJtVDQd@z$_!0nfg*iYzWZc|hghKj3QE)K-G6o#aZ`-E3JQ z?=oNSqigg=qEI*V}MrmNHrjmXEgJ zC<#Xf`6vfRTX7U1AN>nQCvc>fk1}v1;>ceT7xdZZ5gtWYiRV!0=ZfVxgdYPyE>X%l7DZ>nM#U|SYmD6$M-%d_ z{fcI8Kn;pbtAx^6;$59-11HabwA&qs@Vw~#M}s9QAlqziN>9$+TA~Tz!*ahX(FBKW zo!a0L|B*CQXKwH{M>S}pxb@}+@1PJNssYGAfxof9mXBkM*Fvqm4m><_o8X`O@ODj* zZR>CBxCFU0AOrzvaJhre{KhmLe8kf+H)^TsD=$8j846a&i+wV$BP)T2CET#}W1%g& zHF|hmKD3@`-hg0gfmQ^^$}D__;-kff%Cwwf{w--{MQxtcCu~Lq7fA5d&%yD;q%zBv zS0m#TkJ-ikCYW_f@Xfng)Z9L2J+bIo2 zDW1)+TjQ;%pe+Z|d|*X5$E+APR26st4;|6dp1 zPEjp9>Ng#=q*kfcb?%m>3kS2XF%O~#~`>nIW>DhadYiL=IsLIJ> z%o)eSR81zDWhAGMNg_%8?GgSC1(dS|z&Sa`Mghm@+Cga<4o*G_OMjfG!Jk5Kf`f4ywK*vk^RKnU)$%1|Pb3w!*-GQe(xCoRv-K8)6FGwOnTEsw1KerLO(+r{?fRAtz9HD#z#k zx}<42({pCzJe~7Q&a*i)b3#anw70NdWVx3YH)Vz=UGe0dM>6;bZY1CQN?IrTwUSU0 zc`Ye5l{Q(W7>Ysv1o7W3Y_xo1l=!io)C`5_O7D@yra}ebhAp=UJ2=Dy>`J5=oFf@# zl|s|z?85plp>LZ2x;Xfa-BQ5UB%%E4u3gb1rA*6_SUjdO44@;xPOmUwYM+N_X5);B zi#k~e+Oz^ps4~%+)Wd2pWcHJuT8O)#qbA2{pH2Xj++)1>bLQt(&UjJM z)iw1WEqv!y<29wh9LI+%gxL)Wju6WEU`^<$Kat9Rt8Lapk%*oUx5KI(eTMz3)5C@} z&WT~^oKwq%#ab;pt!b?2k234Z*a?XTVkaa_iie!p+?+Pvnr-fNr47MuQO&=m0mc6D zHPKfR^5s<&Q|6O51*mahu!T*CqwO}a(rtoSY0(x>2ZDkV;H?}Mxi)t$q892pXbeaq zJ0;n4VORRYje=0>yz&*qs5Ls6;5aY$%6{0gR5l@)#ebn%5pDp>?qoidD=Y^r5PT*O zMKoi%)*?NPtW6h|^Z zIO4^RHaA4YUh$d*FYvI-xh8ICy$au*H%y*6Z`P5*Js*O$5Aw*G4$L(|Hr+~2IN zd~@$)Pt><~Rbc&j@rjDD);BG~lW6C^mPX5r#v!Q4&B3X!NJ9RzuWsGDgVj4okNygp z^nHteE>@V$WDq|45QdVy68jRiVNz#?W|A67%P@ZFk zE_8~RoNlyH#vZ~fKo1tBR!U=FqJfm2dIcH5C5tM-_6fecQW`buoIZYW3GzK7>I%&{ zj@yfFF8Ud|PPUnAvQ18lU8dWdwKRT_GHHN^(s?(XH;l{nboTS&f((lb%{Nk_rQu-{ z9SaxVSTwCkserd$k!@C9+O`x@v6!7YrQ3sl8*Um}dOWD!-!0%V)>qZW37ezdU~`Hg#aU}y#jMu^kKw&2k}>>W8B%fp#owY zKPaDi!19yl+WV(==n8Hw(lc=A`SMstY|2YECNf^hS02i0U7(6qD?yrFYjOx!Mi~1?>M3)f-#% z24@n+VwSeJuRI$3<9$R`@11kCj=q8Y1GTyTy2~lIPVHdjhnHJCf@v}K^gcD~vZvYk zMA}}6@pMitTVZ~}xrS7mA}Bm*8gzh1(=Wm_y+uE0K(-Vyp~<2M?OQ~<+XFJP?*@ga zMKdC+FZb6LR7n8_KH?P2Q3}^2GiZm-j96`L4pcis2YUxP@JwiC2T<3Tc7@v{MT#Pf zQp!=N0Op$=03)9PARt=j1ypY9g24#E@KiPZvy_mCkg;?-KZ!zmVe`kYbm1k{@9>jd zWIhP&y;sx00vxi%Rr4lXt=jc8yFD7|QSX@oz3v5}Pu)KeP!lMG1f{XoU-4Ygu7&s1 z4kLK=KNf~W@RNDb_CfN_ECfqL`I)%TddPnl5M6Y$ex(IiuM_GL>A@WI#}Bhmo2+-Q znio{Fr0}qH)@crJ>y~BH9NYCJ=IW-cDOzZw+(O?xQdBQ6M`s6n0EveS(!v_xCvY36 zejWXGk$H6l712nplLp6ju$wmMzO-GOvMZ@?VFVx_gE&Y43U%WVUb!?sfeeV>r$1+T zB|*_>hR&|^d(HZA0&%}A>vWVgLfIw7Z8o@zXgWy&J5tCn(80bu^p@od0LKv>agPl; zgXugD3l2@j5k*;+?*`kptbtKyVN|=G@|ucw4oWM@dKG_LQr)&r2$48LR!?4hIE@x! znROfF;knC;^ez2oHr#n9QrIh)V%})<@~v)q7_vg;kC3_(DEMi;{>mWh9(q zw#PblWHnhzvgq<&QMBSOgXhzlN2;iEMKaf*QTl<*@?ugdG-w_|)w?islr6nChYwF8 zS!vz`igr+j@=d+cuiy0(JGH?+GqfRE&N29!8o3~9F4M$wRe+<)|F;J>c%29Lre!ZC zhTfh-(+;*;7)ZMb%n zc9N}^o7lStjUpMY;*lZA?!_O9X8dL3+LCq6bBgn!?%y7+(m~_-%Caqym_&#$$|4~R z#?5+TQ$zn`stR#T@=DaA=EYBB`^cLKSof%*S}hhJbjvoa+7ngh0ulO0^W~eZ$5MYB z;qkQCkL;pB>|UED_j1?C!}r(Yd2wm7Zz1IpC!ztt&}4jJZa?sL2Ycx-38VYEeH^3> zfF^{IA<*}uLERK#vn}m8%X}gU3UUd&VjY}7RgqCC0r5SgIPqd!3WAQjJ6PD^2!3lVxK1m0+Ps=%))Rpayb{-_SU}eF$UK7 z<^`b~ULpWB-gDVz|E-U~9QI#4Ef0!o;StgDZL)7cmvQCtcuRO(38Yz{!kx?V&Gx3> zQ(?Fh`+A{T$p{KFA}{DIl+Hqdt|~xO59tZBL8)HL%c}}ky|M^ugZOr)w#cxQto%r? z?HIBMSWC899c;WTwaaliCbv-ZnEl3DBABnG0O5$whqy4F_bvJc`?iDaK15P$-vZj> zv}#n1N8pg4sY}he0#uuGnc6}(m9Am_tsSfvo=#*IMe&9_g%Tu~1e3use&es~`S#0_ zjSIWI>XTLRs}?WXZ`o;15#D3(?dC$CbgkaakJoPKV5<)4ic5s<{wzlxlx_8@9(m0q zzLz-$p1ul;KQfNAz+LY$mc6mlK0H>G_f8MzE{#piT7Vs~BQ+Av1=4${L0s^^?&@p` z*f(VNj#<>Cl&=E$H*ly~|77pBRcjVaY0gZ~Hy>#dlWPXLL2)XblY9FkUW2fI$N+vb zSzACs31pz{V4INOx&q2VY9eiD^i;=~y2H(yIF$L03`4<0T?b2nR!>@D6KdB6Bb+9O z0o{=cdD8WC87%C^s8#zdzv;Cbl{Q5j5ey|(v$gvc1mJYv;UnX7Jn0%!7H*9U^vNrU zJ%fU{2=81(VL6|D&IM90w_3d6K0bq>T?{~BC8Md^d{^aaPWflF^#+$6pcT6&pW1r^*QKXaP+cf z3~#yYQlyoEJVp~XwI|K?Mc5esb=QE=9@mkQ`@~l$2d}6>6cRkWH^9J`Vb!`Hzy+_c zRLBAYQNP(z&|W-3gCRDBTT9HQ=1XZ;B#lAXy=DJ#INL|Wmf0!!=9jc#aFct~mA%hD z9uiS0Usr132Bc=qQ@Ji65vtQ!AGu4P1Ck4E{+bk9&Ao_NJ1*FIZx#=j7E@W`3Jc~- zPFPZihf_jr+XM)WvRa@3{vjC^!fSMh@gO6{Fp?RN-0z( zu{o8GSTs^0wq|GyPoZAIdo8Mw)R-R$!+9JYJ#~y}f{9}Dh-{FRyE3uIzD;{|@ha?g z*&zzalRFDM1m5_`s++5hfiiTk`%}xClLi$+db9)QT&Y39yT`5M#vZisM~LWTPBu4R z&V)W{KPPxPbspa%ZV5$9QDI`5T~+75g&$i88`~$TxzqlGI#!q2muUPiHN)3)BhBKY zc5UIH91{3C*q-unR&BwcP410W`oEl|^TD>pWb`PAdHDVB#`bw&TtY@kmbQqv2tST? zm3C7}Y6na0ev+0<^EMT|%&mK#1!lrNpuWLV1fS6_D`}cK*iu~1jhrI-z@H!1UAR1~ zx`V}*`xN%UZrNH*@lXRP%_e9`OiwJ-h_-&7_Kv&$iuwU&iwzFlEzQW*VA3g|X7><26a zq#Y7512J(4$=e|7SBbT%-yrJ)Y5*hpp6gEOwyfJoha#=dL@J z{}eKrtQQ__)aDT)o2;#BR1c2qpmm0L{X@7RJR_*6nWeX&J79UU?*Leh>TJ?3{L zbew0m+8Tf;&v_FiG(AuZ3nJ&+@^I@Zh}J7DBrH=TR|jjX2)FtcXp7+c;i2hDMg&RPL-;t273Bm8(9P;z;R)J>J`JwAok?)mb&me~hPY4rT7oQ+4I)98Ehu}NC{;VVf%J+=Kd8CE?|Q)PNiis} zK2W?Kyx<(fL>(OP4C%ELex?wAOD7UBAf0x3M2)UE7oxIKv@5U7+@A>GF$!#)gkpZ~ zxVYeJx`J*0e6E7dUzL7^d~tU)Kjsv^oz-vq2S45ibmk=T=Se14i09IL3RL%{6{`E~ zD|H3A3-%(E;Vk>6)d!ZeP}vK1#WK&*44=%CE=_3@;(0iDY?Za))-3ZxSJxh0@%L~I zv?QEi!R^V4)Tq#_pkXIZBXc@llRD4Zk; zG2UtT+rhf348lwsw$&Ln6QR!}2XwG2-BCJU{B4X9R}&LkmFlMK?QHa+7byDOSSDM1 zh>_98gg9bsXS*H2g(G1DZ)A<=w4s9VQAtQ!oJKM8*QE8;T+ljckl_@fz1B$s4YuII z#8uqLiLQ_KxSIeR0tk`ut2$UtdB{iY>@He~9I+M@tFD6B!8w9v2=jLQz^2LhsuNvb z@4kd`*rBLqr!vs*HS8<0M!gZ9GzI$3d#NOH3>Wl;2%_T<-5&%?_C^x+v{JYgov?u@ zUP>W4^`7f(=mD{qMlLK%8npGClUJOSqPLzzJZ2;|-4VcEXGsIX!jq!#;M{cbNGa0Y z(HQNlw90JFk0rm&c=&C!g(X&EW8@Jl0TtO?r7iGk{J;wlVvXNJZ2HsR@g?f}9mVqqq{U3pq`_j)^G<0zP}LJA4; z1u9M|+tA=!=r$Kkbj|quRh4g1PjFng9M)3x!1Q?+n^UeW_RS&nqMdzSIWjRg?>tKR zVT}aeVwoK`_ooP(?%;|%y5bB}&UUt?vS;sXs>F&3ter!vqn-V`()QnjmI+wJzYn6V z((Qvg%l^{>(BV8E>}HKb+ige`=|EI{M&%33Wh_}Sv5M;2*(l+=}`wik2<*eM~zGt!zs2^WdEiXVf63A~_WTYazw>L2i(jF3rAg(UvT?1%X!{ zfZWgrPq)#-+fk3)?Hp@oo_`LNqLQ+^c&)aO%$)8XNe8tB7+5^=42nm!Gx1;>%;s${ zo8PL?VfKS5=0nYkzagZ~{p9Nh|ICC z{G2$5MI@&LOlf`(LS5eORt-3JRUsZpqmU&spx5t z{h$Fjgl~4nqk1#yTjM;Eh~@sTM*rV9NODmp(>P#8oHYP@pUg0!!hQAuO5k*|e;>ZA z;e(W-r!say-&SR_GAe#f2U~u)XLM%U4z9FJ*asTEgtiwY24X`Y%BLB_+Pt`(ovfk+ zB8B*_{V#JTuf)8E(eY0(uCzrQc){s*s1 z$B?c?#UbYM-ZZF((3eeBRUiwl_%le+?qIJS3`KxioaM?=6gQD$tOSxO`BEXCCBQ!h5-vN){UM3!)dtSK3UP4Ne37X<7 zh@@HohWGczRaeYFaK~${sZuT5hj`gQK(v3yCdvhccu&XS;Fmy>@<8D#8)`G~9ss9$Q3~XMXQZoPKeTK@b|*2W4E*h6F)-Ul zR*y!6z&3%V6zhniO$v#6RusHKG}Wn0akrfvt{h|KhP1PRl|*$sy#s{7w+>CGMNJdQ zd(k}BN*(NM`A$@7X-G&wH4h&a?xTBmMu9pg}ou9X~_QrkT3pqj0S?`$bj4uK%4+&*oFQ z)<*S;Dg#kDUrsJmr1S57y}?`YdP6TIMHwmpMR5%T?m1z;Fk8I!hoRsYbOh)Mg(X@1 zSke=y&&04*$`U+fA6CVj>X{9VEBbAy>ED0-%!XfAYHZmv8*Z*WjRPlNb;*uW{W8h9oBe)`@}Aesal`womp2tv;l*XS&yAop4KH5wxq82-_< zdt>;N2Cafnl<3)Z{m^_u{pi2t^t};yTR+|wk!^<#fQJL?BN(SVc>BOOT!J5Q#shzY zyU!3BNH9MZNFWgqu-Dh=8ojwGjlIyQethWW{#!irzV9FK(Zd^l>aWipu;JRh0OQd0 zeo-EqhX6H9Z=51_W%xxYM6cul`8~!OzD;3k9-9Ago3>2RrVZZ`4YN%dhlRkIdoWxm zLX+24ixZPcL0EljZ5788@J|* z-=`+h9X8j!GT(x!4I0n>qNaD+Z;C9iZYXgjSwynvJ2~v#oKb`2$BmdG-pO!N)i(A| zhXHTBt^KuruIa)fvJt%JWRZgfRGb*x3hm#Oh=U~s@6L+pKs%uzk}(^w@oo| zn(%R(FE$v=m%8}q6YM*XR-0?z=U{nQ2ebmZP?XZktBn;qdW|IAmh-Yb__7onWBqcO zW8_IDF;5yPPPYju?9Jc0SZTR`Q6N0C-rO0sw)4pTE~YEblfuMH=nJa#fOJ618G2gM z@8gC63v%Bjm<0{{KsWFiiBAYVVfaMg6N%46D3hjH*yT$uAc`1Ubjjm&7tpZrJCEUs zv%rFWgkRzOJsT7)T!ahocf9dS{Zs@f({0%QOL~s_Ex}DoNQFI{>Av+z-0FVparu`y zwRpI3leu`xi$7_cVVd&$Cfn>9z^{ba1D7Vu5*iZbTcV@qTLvd=izCVs7>7|Zo@Q5U zZJ#a#7&FQZ-;6sAFc426b|H}5YY-v=veMjtwm9*(O#(OKIZZ8&TRPB>l~?;TLbFONrt*v!iWSea2X{&;n=?}R2aWo zu@TVA+HkmI3)pIbR!S82ZBINIo`EJ>Kz z5T#KzdMVC2fCOUmcwX|dzi3&QplO_@Ry3*~B9-c=8V>*lQpjOGvKJ253PNrDPiW5E zy%Z5kvEaJUr>+?ajIby0;+q-zV$NtNoFxc5FQU)GE#r4n-$P?hv%SE68DSJk&#(y{ zWH_E8KFA0z_Afe+Ae631SYWZK8lzQ;MwLH`IrcxphIa%eEVK%xCs}OgEI1iQK(ZMk zg<6zRcWP9Euw#~>&p*R9v~wf<9VJ4l;9o!?Mcb|5nTmiMK;0lEz+U~6FuI6<$u;{< zv+Z5}1tkd!G5<=)4Ai9pYmaJkbAOi&2{PJ(;p_Q`LF=`6z|ce72(I~&LDS)~ znfN!yj7jX9Ji(F;{ol{o6%JZ2XO5B)lF3HMHs*22)HL5fpcyw=HmZlF2pw#FWe9`` zPSe1SbN?FiTZdlJ>&^p%vTqb4GomLi1Fk(o5ZFQbMMIc>O|d;vLj*kstw0 z5l1Eer)3Vu!EOA4WYnF6G38{9_lJMo_8%mBlYwRUu0i{`VTN#A#Wk=IZFC-$JPiDV z*X2So=>*xg{}Y_m@297QgwgZxQts&c-XG?hf4agq_>sS&v+-KkMKdFCVX%G zbtx%yb#xbNs>uDZQ8V-@12SchlX~rWgf_nG8n9z3bh9G|q{J2Q|#`0f(AGJ!z5M>e*Qe`LGh_$ZR9k?!rhZguPBG)?E+zRqg zJzVBC#&j`#r90y{60q+NSVl_8Y90z^!C+x^o9W03LH46leA1{b9Rqe5h*t zK zM`pO~VJg5ClyZS&5jE1uM`gb2nqCG2(?PcyRLdU1@9Uv9qtYG} z=UO%d(fWV!V{q(VZOmR7p8%~d9ziaYkjERL{25?@SsvewSKqCOG zxIFWMq_WdmawSEJ3YAHyVefT51&!Gxv;e4$fG29$_nkCToK5u32(`TqsEN?G+t_1= zP_YwD@pmYLx!?}w_}gmXTK@NHnSan7siZBW7$sU&6lQ+26AsTm6I9#Sw1e@1LHSg^ z=4Y(9mpv!l-?xM8&Inydw`sH6SmeP=Qb^b|EMzWZqU-t69vkVi<)puQOJuq!^jLGh zb!R(MA3|=-a$-6VqRQH=1u^q$4#B|vV$B*vluU7^*x$8M2*UZ4I*ZDw(NehXoD3gl z9puJ965QP-Ukyb;#Wze0E|KG z3HE7wUF@1HF6dw^Ez#E4HL3nv+TxO|w!D2`Ti)15z}C;jtZeM1DtCNfd2nSz%$i1} z+TQe&{X5Ga^>#olG}a<@c~sSd^}F1*vNl$P6fd1BE)a@wepJJGWm)P^s2&N!p35Gk zK_;w8T#~UfYsQ0{EB#DmsclSGbzNFFc1?6UYdxHur7fnd&)XiS_Gojnalxtz-nb35 zz#aiK=evimON(%^JHRkxLIN(4#>OuwI@^6 z4TAxg#KgR*fwHaV2X?NNBy?K`+kl#E6y8A`=svq8D<+d&U+${KTx_Uj?hNo6 zHVh??b%2!Qdrx3%cTQ=_ilSgTb;XNb`NDYLu{S zUnqnQUQ9_I0p07b*rfRsn*_lyqMG7RehrKTle#R+ZW$YbS$60`4aa)T^L4#?k#5bW1748_})PJrL3TAY^=P<#kjp3i06{LsI! z5P9WN8Ki>3H32u4LXg7XSBsye!s2A;iCHy?Zvcd#U-80a9?pKsm!zSnRcABmbozxL zNF%FHAn=;RgrEX)_;#{2hu~*6CL$~N^-5Y&Kv{7lOlH0 zkdzluLt#te6d@aaiEL>|UA8pLlr0Udj&4xIM>Y6HA&D$F2n2Fohdm})K<_fhY}X7q zBoey1i`|DqOjCK#V&1m_mNz3TO)2=h0eSTgY6%0-43`>Xkx1oOUeN~3<9a}j+S)Ab z30o2awL#wV-p+sf>f7+C`Rd;W+%a1VWq&)zYP?V{;BXKD8dt432 zv6^c*rsjgaR&(NKlrwjNU4#*LUM0ChgJ5~a{`P(+`X?mG>WZa>ZOEXGM8lpy!=@jM zgeDz?db43&WY(o`p%5i{kZM-DUfXjptAmB318~X>f#Gx3H5-1uZ+TO8hR$qI59+sZ zel+DNlAK@#O653YCaRWKf@O1}lsVIt`i@CZ4XI)KT78R1s{2nWMeM=90Z$%@ORWfr zTxQK1aLFpo@k2ZRFowiB#^(x0HY1-BV3uo+;FdZ*mgXr}s zV*g}H9@5BQI|XpNkXLGvG+WLqucc1Qu)Am0vp4ol27tSvK^K5kYSq^6x{CW0??z8uIV1)iW z%XOb^*b!C$NeHDoVyjh7Z?7A|Fkxa6C0_;#HKFW4>*^!|(3A_I=^67w;OG=_m|gMs z%$P=C_}8!nE!0C)k{RgK7((^NnGL_Mye2KG_H0w0I*q?%R)vUfoGu_i9%_OXu?Bn% z7cx9|u~YMyExBDNz0dSAAK=8RnNzoP1)X`ot(XsJ)1#JwChv+ftbZrHVgYa`=|yeq z^$OmgN6_VyuIf^R-}s@}fD)><+pNmIEY}spfz=yANGPCPOmw`s9f}a79bL%k=r;Cv z1+m3b<&85fJ1t6QUw)*u7-?OI2G;P6(-4!C%%4K20R`cXckS3sWf0?AA^^Z+^8FO9 zMjbNePbll-mCk7jZL!KZO*u3+-+a$fzc5$jLL`~q;j>v&GZVQA2(+n=l0pXM0}6ox z_yEMl9(P1TUQ|4$CzG4^TGxu*wBX2I;s@shiD{EumfaK`PXyB)xR8Rs&jEhoK`rfc z&bx-PB!N6dk`QH{&N{Rd3B#JbP)zM`?UCY(5tGJ4S)7lcb6AAdpI{k~ROtMt09g3B zg5=)0GJ|;v=U#37pUFm~E%yt z7bKl&YbSfI+`mu_b_Vd6jk$K0W@z|=aciRI>!ElhaHC9OW~#88Gx!Y8bBr$qH(S`l z>(;dRKt{e*#*Tv>=qIEUuC^!tt)Zo;lxjne-w1c&HOG_ZUfNRtB2(h$8i0S z=f_=>+wJ)w7WxC5(oRLGX}G8wwYyiUs<9B=U+os&LqL1hch-Te-mTEXuO@X-aKLG{ zz}DI??=*7D5fAKe>&>mKu-iS|%JM2xWV;P!#jBlZh#o^mhGbQqk0HBRc^-wB$fnDQ z$20mBz7%j8V#EuG1s}KDu<@ZWAWtu-5Dyi+VdzF0DMR7V{Lt9d(ftZxJ_u7cW_k}< zW{Zj*x*;YyAbYPcR4^0_tkX_-S!1-E(;H*6Axrc_PRFde3LzlxaLjao5Pc!*jOpf) z-R5Zhf3LGacW9b0B~qm7K9)~CHPZQ@xR7nBK}wKkD=ZO zvMOOEcqWXug+5tpwagXjroiDUPha~zz}<;zV0cMvKl#J^X zeC>2x!>^8>3%A8Z_=Z;1BXve&uqCzdfj~rJ=B}xmkK(SUw{Rb=jvkF`u5<~dwd`u= zoO(sjT)`g^DZ5&c)H=%hnz0y}#(^|MgI?hyF0yaBzA)df?Y9|rBe|VZD(ZLCjs z6hJE*3a_h=S1Z#TKFNGqfDRGc#-2PBn^5^ANH-U<+V%PFPWIK|*Dd8s4Hci=tcDiK ziQ7}7fB_@bDlLV0ymB=c92IleHM`V~AZaeRlRaGyP&xRdC%WPQe8y?qTV?*Cr%)dE z41_MqQg~hDqEZCXe8{Z`AC8I>A5Q)6U}ahG(`*_1_!s66VFKe;6(Z<2yWg>-MZcNe(aZ9v z{_#6MIc=OGv2ljdkoPTHihQcIt~omlh2$#eWZTODt%rqgW2blR$1VqQ+YqBw6-c0p z{Mfmcdu%dFIPNsNu0{wi;x*eK(wfAL$>mNJ2+IgifXM2(LKVmiGT;L#qIU>vI;4o# z?3#+^o~iPST5EF!>>xup8Q&hx-__<@riHr*uA*+AW+&tR6l(`nP|fQ5vK`FkT3lL! zd{s`oj-nU7aHWoiV0YsXu$$zXU(gz5Wr4@|0E__&(}*h0@#zjVw-(asI(&TPzYuAE z#uw8OHTOF{PajotXYtVx-N412Mwm8Ji=EbZmO?l@$5&s1vOjn!GhG?^1n{#WLD5 z=T@xDsB4*{+hCl5NGyu7YGqT)iIWV6t#`CE!U9DcusYh}(8UKVe*jtT#jvI%(td8+ zsq8IG>NbGYoReH*XgaUhM_VbbdQ&QerOHa$R9Ez|KMz|GKD^)s}w@zbYT3 z05ZQG8tS{QU3(TK#2xywtkD0h&;7m6L+i1DtABz*kk^8HDb+4ZRyukiZ;L53sRop7V4RD#^Zq2cdw?`x&gNq zd`{krdgMM&yOZ0mQ!~~UbM4-!B@t0iMxDMlGNzqfIXI?Od4H=ZB&shG^|qNtZtxKL zH3WJ@ItB}mBHZib!5(2d4u%tRm%bnnb2he$@`O3D60uUp<-igWsp?o$=g|6qEj`AE zR|0?%3U`CQ7T$_Ok%#;Pk!hgIEqbc~=-dqpu=@vah~h9)VC$eC#RI z_HAMN9ibpbDKa7##VN0Y=5$LBL6g(wGy(^($f}sX$#^58W**&0!Kq4C8&q++=$h#IeQ>0 z0_XS`0vEL?#n*{VGRYLVxP`s%5K5`fwJe~G52Q`FTZ-rdOa(NlA0VzW%i+4*q0c|f z$}wu4Y*+=D`?Fjp+XZ1bP#CxKF3Kptgt4y{#D*(JRc~M&)4&Z#j*eBwRxUjnTfXRp zThGDN9w@0$-d%R6opkCma3>Ibm(_B( ztSIb|?DVT$*LPFwLQsuQ;hUBa>)hzvb-dR|TfZW0@yY-q4p;UEX19QqyTz>*raTP8(PZ`=Ox8M0chr-Hi^|WmcnhFzN2eZKXDIoO~nyB!*{}6Ez1Aek}icP~^eg z-LK|64yd`+d1~(a-5%VyJX*YW+1Pe{;qyqaNBJDfU8a*wsy3Ht57vebwSs~okt3~B z-DkD5z_DKLq817bg3UE*&+~AOaa)JOP&Hk+%WO>;J-UQ`HrCYQlxI6ut3zAp6*w+W zHI!^Hzo1ea^|ZCkgpoMjLgP#Q#25oZT*bGre;&fv2abS0#TTOzQXiGb3n@$WI39&# zcN4D25TZ8MZ^(<5!>4E6?eA~fxI=hoePVsGJe1!9qU#rgYj}Fk0msRKuF%Rptsry5 zxetw4#phDaz_&;YD;0XQ#NL(J_G(wojxd~isg;+R*`uv*z}R8PHws<|f!~YKX=SOf zTKR+2a^Sj(zaKm@^v{Kzdi}R-Roh(Q$9r5%EnA7G z^j|Az*M*^36JXDsraJ??D@YvUT)%!!{cUC86}n#-X30Ny`6ClHNfTy6zr`1 zUQJNn9R_@Ra4&a}hu8Qi$600Te_En3Z9dm3gt|n^!@8GPJ>a_mA&;YQxkSHhj%m7L zv|K_5D_T*lG)OND#7unFV!%u+%)Rd6HNbFzT}5>gcRT)#C`mGB*<3H~q2hlhQQtRL z@9C8^_yWu5XnlP{3>4WE&ghZHWzUv-$s5nHPg=hE+|%m^UiCfnkX*Z$m;b;TW{1`5 zi(oG~$d^hIkb$6%jm4#2UcS8QEQ{{Qt@idBx}c6hifB4&B9}!S8-#G{;#-&G`XY6# zMslLiqAtu}I6r+h?0x#`)zJr9xVm_tlzYL)D-uxgk593|EBhDrZzL0Q;tR7>-mp3XqRP9I0`nmyhn@ z$OA|I^3e?(dGg*)jrR<|1=5o)cPR5W#LNI>U@xbkm!nqG_@P&?*#iA^sv~#3&gxDi3`DE64VGo@} z#ruFhUO~3+Sxg(b!PR7U;39<~2Yvw^9YYAsAVD^k^y{elsSjq!kw@3rbqw0@dM~g< ziM<4Imxgkn;FWy|Y|*1WPZ%sH>pf8`DEkgSw5Hw@%utJ={_^q!<%f8q=g>5Cp5c`vKT&h^88qPkGWI5L zQB{5X@V&D!mlppbPr39Mr1T7EY1vaI=74L989Kln1_ZO^ zQ85Iqr%)4e%LQyuE0;_%h0^Ll#m*fDnD={TwB`T4@8^9#d@eI{?z!il{ruMNug}E} z@r0bS)cf&U5F+ADus5Dh)>NhIO)MfH=Ou}}Y zHqBhAN`N)uHs3Bp(^?xlVPFs!J~*vUT6t6q zN}(rNIw&LkHVR93n%wH41d6mx3x>i)b_-7jaYH3}qOd858yGqhexIIfpY@!@H+rC+ zA?2cQG>97;`W0#Ijhv$6f%1(0d&F&+c$KVi3L(K>p9mnHU4G z-`~(91WhreBvMh)AmoElGf;L|ot-QYbRk?+bj;%R95yXxp~fAS=?%nmv+`cG1E4aU zRv%}&OkPLq!4NJwA*7g%_o}3hfR>-6%xYW|&+8Nk@1aNI2pptifE8ZTFYF585(ZsH zILi9QfQpL^lvh+YDRl}R^~qqmI*UrhBLeKM0=+wmC`Wdhybar-0h|^~Ah3tlkaD+P zIrJ1>y_VG_<)4VIFkXa18@q1xnn?@aTX|Hx&Q5JynLV0+)o3PXe-3TD0C@Eya11XK z-*5|nPGV@zkswi8!Xz9))h5Cm_a`_s(<&IcjugFzu;8gWsa1Mgs+8j3l_374T-Y;! zlP45yp57(#K8nJQifh40G270PgD$Bxg+ETd5tDV9ycF1mgB-$l1GwhZrkjM{XH7JG)j1O4Naf`*X?U3@$3~Zs7|JD>EqU`mc!%kjXnEy1az{+T z0y;}tTs%^yy5I4W7>Vz+taId=NI$dj8>N&Wq?$`wQwSfJu?6f{51__ssWSS~QmHjV zca|)34eLz6qJ7nPk=%78U=ognDuK4;GU?Y^MO!p0~( z;)Qj7kz90mcT!coK_9c&EBcyyg0Lti1-(d|y&Y2PD`+;Yc)55~+{SL}lv+38#iLxK z{wVbYoFx;w9d$~SI@Vp4I>%Mmtt(c^nJuqr5M^N-jMQu7OaiW()x!KRZlLrys6BHS z7n6JucmwdLeCbxF0;1Rdbt+Iwn!A)29Ctcfsv%#(3OIz%jm5&5Fs=x(5T=K7VHp+} zEIQjBTb$bPtr!$AGv`Y&D0+kVMapQNt2j>P_Hk9wCS|&BDU)cpE6^h@n{GJQ!*B`j zg>!N2G~r}87nQwm?P1_|OW`rebfpy2BkM9LfEo7oHh6|;Xe8{@WLqE0=j6(95{zw}w_3t$3zIm)&I%JFxlz)iOZJ(#oY5={T# zi3#yl(Hf}dO_oeUSH>FdcD#hUEtBdoQ#H-sLQvxc8LX!Hg$7C%hRbI+sVgO4UlmQj zUc}qRmx|&2mSns1IZV41_Vno(j~)y>qfwxeX;IXo zZ;GoNr4IeGBOBK4U9%oZJ35p=O7ZkzMxCN6wjkOhFJ&>`-V%O{;?m5|w0R-J;;vEv z1wQR{$x^V70>(dCez|c)WSa6-8Cpo>SP8gGyw#W0mRr zB>pr0X}%JsZZrqQ)-AddvbunV#jMTZx6BD0NjID0OpDcOv;kEP6H zoS*9Y%MiD=!|b;^SkGf(AhOK`I8aEmEjQ-#ULEo(Ma4A}(;mjZIFV zWOUxPP?L%`m<+}uutUFKA)d1rnj*rgI+fN4kT)km5o#(|^AU|)g$kC-x+@VnKbw*& zTvaCt(?5$}p+le41LNO%8D5M2w$=PI4G}t}^(497_xHO=1Hh$&-%8?f<{RpL;Oip? z4(7sMVY`k?3_J2sog1}>ZPKvd7Vj^T_F{Iwr@#40?V%98#?_#G$!)P+ZQwy-uvf)aVEdgi5*N*)9Z`0k{R{wSv6PlxgY`T9CFQ zj9)Fd(4xes+GyB=E30Cjw`H11NNt?^xW7Oif+eSm_#OzTP+EOzT1bs37-G4B<_pmI z)7RbGKLG856w=+UaCh3R{ejt@=@ihr^#;?l5yyrR*H2JKJW+`g$R=l6aPiCKjJ86~ zyj%`Kt4z+s;wr)Q9r!Oj(jLQiZ(PT5iJ!2yl?opKR;ThZ-ZhB4*0U2qJhi6NV59fs z4rs`Dn@!7DN6*a5MAswq#B$;6e}&*U?w_(Fkf;hT$8qEJ|MgF4Fz^i~rR^BPWXiFi zXY+ea%1Re$0V2~Q4KyB0D(_dT+0B$*Ax4*QJ&uc(oEHUUJQpwV?Gg0xTu{gw9d@C# zC$T|97Ev#b^m>5MIE1`b-`?hSFg-O$cLR7jz;&yuw+O6}?G zF{U-S(LjEXuF?0%7zs4pTO?I zAWTi*lGvw(R}#44swavsh(Q1tHr)M}(2&3dVlO+Ez{Qv^kxOosLo8)xz1jBdysFf| zdsmz$R&<;SpQHN?pfXMa7|eiSKSeYUQO?BYdU1sNjjMT8$&Jp1izs^?UaYdb-zmlT zE{@LP%f#gRxIK)}O5W`KAHcBu1mBV@SXe*gqSW>2wk&=~1RrPH4_sRV_Vgo2Xd@9W zHRxNWt81;Wb_kdJWG6Z4WQH*iOY5NA&cdEJ1Y)Fk2sg6yY^p8vBw%duA`K{B*bL2X z9#C=uj;rU3*i=axy%%UXeb*2H7q5C+%4fyPU?FC>dr9z0SHld4aphW6 zNE@V6TOoD;QG-`+vy0mL$54v48IUhtjL-%Ma8!Ni6{PqG1Qi(5NgU20HK79C8*kLX zzYQlN(-m91n!nb;RjEqf???j@my&5EagKz2K2?zi=!uzLzg?J_gdOtJ4z7ld&IFS> zMPDR+NbtQ{5tBxdcHiXYRgRSBR6+-2J~gj2M z!2SDZozwlhxvtRtd9cp;`bDn^_dcu3Fol`eA?EIVIHDs=5zAk~QyHuJBJ#*UH1h@F?07Db+p6lK~L0Vn!8uySFE<)5eu7F zNz9vJZ6vKn-?lF@eJ{#@JngM~(r6WfwS}+QK+5^9r|~YvXS59qLW1&!%ZCb%0%>nk-hWDXH#wj1R_4 zYs0BYEdn?on`-rylP5H(ZV8VK+uDs z46>l_drl0h9If-WL12c`Qu{-62{!r-25!1gTTmr7ylpb~z3sg`@@2Tc5A4sz_gVN( z=X6=G1{|E)8iU2_@2<~x!mmTQp}v;9R)ANIala@{6cUDU$*e*6$1rYI!1~p2>V$P! z5vC(pXDwq=A2fIf0l~R7!zhM!SXIhT%NS(kRomh)fro zg7u}z6rYO3s?$99HT!SB9{<~~8GrjV?Qg%b{`SlGw_k=xZK^f%i#G3DYuJkhEO9oC zO?@wu?kp2US<=1BAPd$i8?4yfUEft4{fM(~W*(~!CW6GJzbDHNq}vBB09 z7|;M~aVkIe-*g6q!}zOQXiVXT7?OGhLOZN){$Ua|Jd~dgUlI<6OUq;eFM*~90Hjx| zWyjj`Xn!w4f1hvA=%Oms)&TT&w^Ilo#l_0;tkxn-P36MO8M-#I-?`iLRD&8|ezCUE ze1>jUC_ADJLimMnzq!{|AqMDUfZbn(xKd14o_kJ4fT8lKrFZBSrGyfy3V}?`-O}1f z8|J2a)qUVZyL4yBsJ@@4s;xS{5L6{o3Nx@?7x~}*8`(@u7VkY7G6#ktb2l&KZQ!gL zar1}$1*QsdfPSv=NmCMnEK|)GfsX1a1Sidc)Z%CIvHO7Vg0YrFKE-a&?n~G zV{ya>l|FTaLmyE$@8tTyJlp={!$ zU1a$IwKWQYo;EVrNjH_24xu~^@~J%_ET3`nyc_cSH;7Z>RNLWHDvDXW%;383? z&^!_%qd1zSG=M(R(nc&j zKVMf{<8*Ww+sMYAXF5=84Oj~pfBXQ|o@Y6(;hXQgT}&4wmDe#P!%&L9O@rleTYLmj zT-0Ii1s$fFhc0uadRE)BH~{XiHlZ$^^Hy5&=AxgWL2FLuUervphgZ;2n9aj5B{zyf z<_JzN=_?Xm8iDpOT|IQ+XtVe^JezuyE#1byb;=^q)&(+KX_V5tQqIyJ0P;Cxx$)kz$93?jbYiMsR;L%dSPC8uAU8kEC)yW>Y%LJ;ePu-NN zRdy==3#?>f+sKm+pVE!jv#>T~z2!IP78YZ}9Xxvi7I>5#OK)CzU6Q7TJR=bAnBaK+ zI;~z%Y@jX63>B|TLx)Y~RNp;0`)9HkgQ$n;52K~~;}+4NWfBctn~G>V<_wfMvGXKO z=#Jg(zdRCzfp#}4r)g1qb)Jt2T*}4<*7%ghR1T;Ta%Sb6&zX1~gaUSegD@eIpdvGx zUB7>~vrHVi)O$FBhYk)B%r0`i5oDc24TR)2QYtz-)YdS{vZT(#@0(&pN064*Hj`(Z zQrelAYqXkSy>zuKM!W4m2BNEiE%4v$fVZe`1^4yOi>TInNCOogN$hXH8p_e;Z({*0 zAcezJkQ%c7PtZ5s7Bfgir!m0d*FMR#z!<)KL}I4BJTb!#YOb9M)zq-cxdYYc=Ar=b z{J+>$_jWD2)!7b)cGhQY9#Tc;BE4`!{Wx}oQF3qBi_1Fqn6~rnbSt2gFyf4kMrr9l zRvHN?8l{0oiKpQ!JwszQHmC1fuxZ66Tjosr!hEqa0?2sHZ7!0q|B|UR^FW);lvF@X z61BT(O%aXzI_H4~thb*NliOdMEFxbJb|?CxtY-Q$7g@0Xaa2zJ+0OjO`H2laHMA!` z%WowGFtA$H?Qk1jyp=ylD*ZYU&i$|*?Ak-=hgIFb?4h;%4onr5Y6cf)skn~sJ~AP<4*c-L;uf3uT`4Jh?5McB#x0Twzi zhx!95D23EPa-EcRqO8Y(NDLt8Cxq)zYlOU!0F;>4{3VQC2Y{(*A%lBD+@CQ$Nqk@h z4g?_>zrQ8_fI^&3rRFv}*rce71v+R3Z8Pw~^DZV@qYLD{z?<4h ztLu`e)x4AGFBFf(Nmh~P1MI_O&`Vlr7^tO>iV)MiA^>uc5s2&lEwmK{y0FR_yv7Do zdTb{2b)h9IFX!nrwqT^&Nu?{e#)v#P|Ap`pnxg3ssz~J5QsN90=Ql91p|7OW=f=ri zXCcef2SrnKnTniCLPQ4VKdd6}0lDxDA6#jN&(J~?AL1_lSrnhGo52U-H(kHq^$Bw` zaJICPO?@14&EUiF1nhH}@ef4|SN;;dQ$U%?p5qpx% zouG=)19rk8o2@eu+bV@2_e{K;W@bxbft~#7^ub{gP=N?eCT7c6q+ECYx3lbz*>V*0 z4V^72OvFR>0p%lf0oAmxneto6JGYM>MBl<$j45>%jKuqB^QI$p4FANpWT=C7<*WvD zu9mJ}EFND#dBenYjVNuW<4=3XP8$0cpl{gtkV?6G1~l|9b{B>IEVq+{K8>w5j6)CG z$@~4n@o`-AAljGz9LU6+5ogb^led67@t{A~^_%k_6}%qek}zmld@yX`YQ-#|fwqwU zh@L5E+=f^-ATTQT!~TK}914CCI6F~M&VYiSJd0V z5v<|uqO~}Lmu{xdR=~{a6SwuGvgraQFlCS)g|tDFI)jhY73M%<@#2@LwxmSHf0je< zj>BCg71pOqfW9%kTk*m8xSASN8*YZoi%@;!E{i)-j^VNsORvl=N$4w*VwSGU z4mTk-Ejik+15Uk!m%+q3pjTS;gNfb8M9+X+ArG{JW=FaX#xsX{OpP||u!|aHRy(=f zqvMq^ijo9gVY^A{dZg`)PO+J3S70USAPE`Z6!wk>bMuLCbvzdg3PsubZax!T1Us6O zfV0TOcQ5z%@V+wf6Wv6_?idRlDKwT{Pxl(yb@iwh?DU6Uu@^UfdgJx>>k^ocQe z0xCM>>nBh24!-}y*MBMb*WNK`Qvx*4t9^P0w7-imA@t=_KzC07KUm?=V?LfD@ASkh zeFEz*z-&9fc!z2$0F00ZOP!e2L6%DPN zEl*|*#gm^pFQa$T8W$n@mrS3u_%wb=+smLoJwfjFqUQ`xq34wMj=sP{@m?^iPgWtZ zsS0N0Ov?$$sa-6ol2*t7(Y|Q$k2y)t<>toZel6}!$-w{mltKX7c*CRa6nVF22A0+d za=KU2E~#PKy|4_!+#)BYY5q##c>|Z_|EAau#@Y%3UfDDW);JpBO9MC6-%f@)zqy~B z=1z{8$c;&?UtFwvj8|2{=fZb1e;h%OK*6@#p>JB!PX5{Cr} ztBl+hb-BOgDEW^QXd*8K2!S9%Z230OM3M(?X0$_a4b1=~nK&M~I z1!6B|N|@O2y0sWeY8P;kOoJ(4Wb+CgQ~Hd10$e1M91-ByVtA(f&s<~Nxu*Xmm)-%D z53j-`|Fw^+_AX(DO|*NSqa`y%7oqLNZ!-#_FD=3gFG8)G35^0%N@viwsj;tKE;51#6VVl1*5O5Hyyd`tAbUzHtwz9k24EBvP0x#~2E3LYa|o5X43 zFTzEhb^@(QAOz3!?MK9DS{KBM@YLo2BnU<>)_jt@+9Tn;+M|&xkk7+=E|O|d0(}Bq zMOS*lcQG-3SgL*%Uy`v-c9f!eS^j~{3FIndRLR?dp*1>zC7fm&WNPFeZpeUv37h7R zh+92vXCtD!4B51P@ojV)AES$eQt73VFG+GQRHF@&m`O{S6kP(WPTI&$>6k3T=S*g5~F2^=9$SL$2VYKljkvN6O$&g{JBuj64SFr9ar{Cd+ zZ`&5o?MEUi@x9&seXi(R)Bem77!Hl)1Mx=2g255lXkY9&zHlJA=4j7R)y#mL_D%85 z(vxrs_oTm%Pe0s0gHI(sH@WC8#=?luvr}n$QiaCJ+$-J#pN1d9Vg>W)a$zjbjhCG! zJNkr`JU1oyEAn+erQ1Pl_-z$m(g!tV#u|moJQwEsBnF9^)doWP{6nuGd6-LAT_!KM z6qO3NWM>HzALa&lA6&@YmT-3R4~Ou~!(5{58*<1YlswECr+fvTfEx7-p)zj^3y9L@aD$}4&pldVH6hkc&UBbXDZoHXF z2oPY@Eg`_CTQ=Z#e}AB2a3*GFJx-6szWioB(h_B{@(6?r7-YlJBK{R@BmYj0rr=b|$(lnlhHyFetVVM51k@h(Y_LzDEBOK8u6 zZQ(B|_Rc6<5#QbEU6TOm_*ggO{be$s=a)w?YuQ=EQRS6J|i}M#xiS*f$vY=q$ zC7gol&6WJT1{OwMph{HiEtRA|sLbY~G{2-o;cWXw7ipo!xaa$Y6WLIbY;+30WOK>T zaNL23)f8^Ic{F$q#+QRydUm^cQ=qV9aiC2j1n%9lSYrbLtUd;s2m)zve8zTmR1jcr zx4Tpo0azj5kUj?k0x|(Tk-_^QsGmeo4`zj%#Ob1fRi;Z@>{FwR9=OBn_BghXZ2I4O z`GOd~G+f~?Ft^_>R#Ewo5IB{a1T(>lE@AFeE;gWcv40Jl##w6@1_*wZEjN+8W!AVWV4@+1LMvJkRy3f@reXg z{t@!B*mj6z^^+RDcMtUg`w$82L*O8BU#^q{xspGm*DuNpPww zA~uI_p4DL!9(jZtD*K8&+%K$pgo~bG$t&)3_hnaqk;Ybl=ED!fO%M82u0ip@81E13 ztX&+2J8W9*!eGl+n6E=SY8OY+l)*GDPzcx(V$p2*3L0af>k-Zn{T2D8Z&8N|6H5z` z{n=iR4bqJw%CoY%LUQL<;ju@#k=m~iA;Sy$V>`(b>AQaIq2gSh5}!)?Yj2;h<54aV z0_Ei$lR(@}xDj3px&@ZD5w#LpuPO9nLiG}|03MrBb9YzeKrwEY@%$W!_j=5yAUbQ!?G`Mqrtzm1RNcXn{r zRk{!xJDAS9F?|7o4^qZ}o`1vfT&G`+87~O2fh0gRcR1JZ13UIC#tvUO6Y)7%UzM8; zZ50LkbWRreHTk`-cClZHHSI`g)Uy;|HLe31%X11nC;wkwe#oVRBJgx!&>Dqa7 zf~@C>sV|KmpflVFd<@&)NJ;s6_-Y^mso^WK%n4%<{i1zz;|tPl2?Ho-8jH0M+iu{e z>BjOy(b{>vQSFc5J9R0T&`ZmP#Z=fF-~=hHo#b^Fp4C@}XUfl_C=|jv715R)Dwe&! zn+leh+>jB+@>cUcTfK)u?h%*X{uLseE-+QhQN|SG z=R)5VQu;Od7u=75)t5h4%6-kmJ{L_56+kbQo+7JV65i0rxKjc_VxEGL%n9HiDXZt; z`G`u;j1$3xDa)B;Ws{7L7ao}fb6@L3y19Ci)&j<4gB*u zH6*8BMG!*|@L`6+$*m}{dOC{L(DjCK+$#$2|AU(=Su2)5!4=>T`M@bW{{%Ny@~J57 zdV({IvqMCah6(*(YQ64AZdW3VMNl=}^68>U;=}*FFCS=9(O&lF+;CQY6^!K+G4~1a zPhukdpEQEf%8unKYlxwaC%L$| zE>R0*?FsT5sE#q9Ha3CkP~rDe{SUdHp#g-Gg|yjRcEBlY+4oE-yl|0TCNVK6#_o_fJ$?1+%E;H_sw{fv;UKy?-_ z&gPbQ84*N{{+K?8i;x{787|@ZIb6K7kUS~~bGTe}p(%aGEYVv-EqDakTo_jrBF_CR z<6|Pn%rP~?wsy>1?h)CyIrd-|;Q^#wk4h6iEIvgzpR4O7-0Hc$H03CX2(NQ_q(DOyXT0@xaJp1|*6ydgzW7 zWdCnvVmzQn^K?NrdOR&{KZB(ZX-#OH!LQN{LfRR!tslpY&Uf=yWU#|`Yd~34*?ajO zZKT$suwM|XbX1nuy_Sj7md%jEo#&ua=zR)X)C%(YZ$kV(xyOcOqWB0{{{(Dharpc8 z`9hSTwoStcnBE>yc?hb#(56J5iSx6ZA!+@>hyUc3%FdHl`-SlN+}MaSPy1v{m=ySMX*b$%W zqZ56!Zc!v=v!0fe$a7_?t!&!7F#nR-=z*iX!rB~&vV3FoWp9fI^>2%x!(ihmt`jBK z35QjjH3M{(Z7MIvArBjXb~K?~G6H3_&qiH*Z?kf!7TW)9MEZ;~Fc{Np9p=u@l=-^f zAa$ydqJohQEP*io&K_Eisgr}R#GyZv+o|KzFd;6N3k*3!I@~uaCf~Z8jFn5f04&U- zxo%VbC*Ww4%V{I6I!@=ibv7`2Lz_xa=%PqA?sYL3FHh|icI0yLp&7c_{3m%)yb2R4 zwAaV#U%{1~AWIxVM=rM#Q)^bQ@a!{O{J<4hR|rC>nF8tcz5eT+DgcC0NgNY>hBP>Z zUC+Q|t4cWb441*G1a<)zJov3VPB#dv;$>&V)=M}he!hQ9fX;Fs6O`VfhxJ1X;Qm8} zgJ;O2&i}!KT7m@(?HYuDpEy!yK-Z)SD5GN&g;jAye5rk27@G#j_^kjHM?cbD#fYIv z!<|vK02m(7**e7OQxSnJ?mSt0f03&&F83FC30>r?oqldJk1ZehZB_bWjmxptSCEif zSm(mM1>9gX{$;12UC0HQPeZZ{DCc@V;C#N&H}yJg_*A^*YL7SSOAn#fis@TbViZu8wy9-bB-ZvIcaFClZ(R@GDv9ygvV{*S3x=lR>HT-c z$eEsba;6?v7B2s-SA=~FvA13#ABe))h1~41v>+zt!6q>R)^Fhu7zI%=IhyhHO%0ry7QkQkM{@*^Ef?QA(Z8DF`6?Z*0ri51$;8C?NNttB9BYdJgB8- z2Wk@q$+KLh`8?bOF&CR}bcR;xJNzwymH>;3B=7fupRI$+fDC>B8xM%A6h6!w83$sV zoupED`(Iof&a%P%!hin-Z-zM22lcP>1K@YWp{y_5XHBNPM4YXk2)~B0{G={}bRB+4 zV%}RAUi%Fxg+8f>Pq|FbU^d}<;2$zw>x(#Rc*QX?(&1gA-8T#yer#I`xQ1gOCJIf{ zZz{vNTiyzva>xdf2HWR|-Z|d8w2=9z%cq%7G3DQoe#aU}z~k(k)f=Y%P2kZ~_&gxS zxhV#qWrnAsI9kxFMq1Q4vJ(Y+3jDUsdzacmi<{;y>w>$ii)~!BZ?w8X3wy?*`s3n3 zR?mA^w~8C*t+=<*XJ6;}2z@fzNy1)S$$`+pWo02T+fZ`6MlQW0GS&%$#_S<*^2 zx{!*aCKR5P%CXtt2NH1D&^)cA*^$7;BN6Fc?YJz6S`m8v$a#5 zps__kul&TQUwZqnr8M^qbjUUbi?Y40xo{dwUn16RZBA zx~*0X;hV_2sK^g(F?@9<{H==)g4n{Yzs+x}e^o%u1Y&-8Po*f=Uq%$37dHSGX-tce zLO^enTEuN5q7j-|xt2x?saHR$9HdmJeU(jKMPBRF3U!2fziOpwjbu8jVRtf7UW4Sh zGQCWpmdRSAOQlap!@PsMd$`@o0@W1nTdIxB3)mtuOsZ-oDX59MM|g9pnoSK?&Eknr zJwU)(J;wxCFQOo z9jdJ(8WQ-!WMw~#$##m!dN=@a7)F01wrC5DFsAF`R#R}ntD-)Xj${Y;OlI?bKOSR9k{mix&G=I+<) zIBb_{+ZSXUWE6DLn1Od8)qRVZahkM)nwG{)pJ!wJ_>=Zt$d5(%$>-WOY-dE>|aaX91{$ z1lh>>-dvsHL5hr~oJNY*gA^rAIShlB(ZajWbAgztpY$sKn0Gt-3iBsT#s;>>r^;+% z(|t;r;pXnA_MC?KOxCs%Y^R^S-(%beBeNOX-oXE9+t%a%xccSzZ>aw_?pJ;6G`@ge z#`@}N;VR9 zVsudZF*(w4rv~yy_dWS2jXs>}Oq0lnhV`tm3sWQyRIAT4n3&fx1zGjx6$Nzg*xs1Q)F& z6I}~U>`3}R-r9FfbFqnjLDmUNmU0p11CD4&k)vu2P%&I2XW>~nLPsNeP$Pz$wNcn3 zTHBb-lvbGn5My|0y3Ta^RR5cv7ij*5bt>y&VsXND6m|`+RF>biFae^40;d;jv`^Ji ztRaKmMUEX%ZS}dmTm@J zwWe%64zoj;28eM2n9=IBD}WI^v8!SoS0#ylHh*ts@tu-&y8Ndj*;^9-Y*V(0GkM#U zg@(p9AUB0Jl)!ynlEB(kFFc#irgnk@S%N^d7^YE+O!G`p2(>csUusqLnFi0fP~s4R zUgJ{D6SHxGqWfFPZ70mk_OockDOj5_x{Rp_a5G^x7aFP2q6%h;uh}USA={O|p6Z1E zgt%5!r%bDipeoOmMu1&sGx4%}6JN?{XPWGf$(cuSB@C4_J5m%(GOpz_<;?b3a%MHI zm(BS1EUqQr_qk&6`Ite$WFf;ZGvG9YYxJYQMZ@R!)8))IT*>%-2%j>1*5PwIE*q}s z@$iX#1fXlUig3Mz`;Xys94^B&I3?kF6W@momNWbDxffT-LkcGJ@I?SRWO=R@e1;|{ zm_t+r_Wo;N>OGpEAOkxt0#i~Jb_eQ%J+wpw5Ssqm z!&N*AKhBAFqkwJJyrNZnsz_ZLBrHKFDwkh~a8;~d5h&2jD+u-lLHDf;{h!4O;BBd^|C719>C=TDFJz&eZzcQ1MW(cd#DX9lYCD!HBCal-hTJ&t z;#FYJ2Ke0Z~H&%%iaXR~jv?nN_5IBbM1h>7$srOMN_y+^94dxu7m|7lsZI2_dKy59}oX~`T>asn9&B&DL3H;v0+c7YEF))#saxXf(qCqTT&%>;6eCmjYePlq1 z;cnsvCLWA}DxH@hZiqQ_!A5Vu-q#98y--jb6wR^Tm4uj2ud|3YAhAv!-(*5O z@M89@oSo>>qyjeMt-Pdy3Z&JVpN1yjxu*G2w2Mj zMRYg(7{+&(@2Thi12%_p8VUUGp{-=T2v~8ZXoBf}jUbK(D+4-hHcoB&dI?@XO{5+O z*YNt6o9MAKzWYUB-?C`K7l1URJxF5@U|;;VBpUw_62T0Ka(9`C|6Rbfau}8O_=V8r z#>vuG86{l~KRNf0%C@Bj~_uRbNBf*_)Y#j8Sq|B3g zzDFI+S+hY>q&U@hU1=}}w)g~0?Er$;L`RtI+Pzu@66;F8PmR+Qn&&hvH-$a-CHBdF z64K;3-alMTk&)FpuDZ}{WSv}Exj0^XPJDl|cVlcf6RU!fpSJEqKL=GJZC_qdL^A`*;wT;{h?IMRk^=0-c9^YE;%$z@cTkzC({N!IWn|MB<$?^wPwx zXW&<(=ZnQmgARt1KSE@*s$1Jy$Btu@$Nzq^4zWYh6&M*v8txf^=Zz?o2rnkwe2II; z+(bm!WWI3-6E&`dDEnnP1t#iGV1s3DKJ6O$5R-5mDDp%+uLlL&f_Vd;Je`Fzxt`7j zq)@h4n=V1hgFKWi4ocU9{HAF%&r;E+>PJ%qwzl!zGwb*}|1urF^Q_r49LApTH!xtP z2=J|l(erU8iNNB4kbXLwBXtxx%-i*`BT>&r!~XQj>rUy+O9KwydY1({uH=oq@7>Cj z`t_{onSS$T;r`olzd|U7n!D0BfG(1R-;#La7)YCXORDnTD*?1X#D;N+C+H!Z%6$jK zVd+>#_aJ=c!(FkzNU)8BxnJ4V|FI+T&sXaHKVB&XNcI2AEBn^}^_72nqq*zmEeY1K z4DD_q)_%Qvbx)phTsv;4r#;f| zl+n_M0z!8g9yDQT|9d7j8c1S#E-9Aw+YQ=?59IP&>m(n!`^_A>_lp6m5p)LycRAMl zKfU1FHUIY)JgBhYFBKl!Pj?e&WY^Jw#307xq8~j&ncDZUL+|d(hQC+Ce7_!lR^#n+ zi0dic41Xh6>Yr_W1Dot*h>Hg9{DRn>p_DgZuaJ8Vp5a=)>E=v4V%?l*u3o(U6@q+ZIV zUJ}hR!@kT_C98_ww0=;VEHB(?zSXgl~Xrt9!Jb_*g>V`j)H z@mNovXd$i6A766^cxnpgL+sR#K&IM2yN(KkT9 zJU5_)i~_W2_yH+hFXXj8W-uiCW2D+KZVF{AtrW~CWBR}ni~*;G)5en$j+FW_R2)sy zXdZuH8aONHKz=foX3bjr}lMl*YK7%ij}9HNKHYJp7__70dy9-4gg zJA}#EPpPPraOI_xmU;~3u(pHJqKlp>PlplPXT76%?{>H!mP74tLu} zGs%BtT0UJ%qXyE>rR2dBkOxYT2Ped&0&Av%m!Dl^qE0&rOxh6u1*xpBM1Dck-~cIi z?)U~edW^`Rawa5-QzCDV~X3iH$!lIjqytpQd=NekK5 zLoHTwb#zC84+Vx2;yCwyQsI~nwt?<27~G;3X!+@|dZFiAV9)R2Xm_{ySC2ILms1>& zcX!YU)=$1`QbKVN5PIykR8GO6k0H$02Z-2_+9SUg*u!+C^{{v3lTvT$B<2JdbcA20 zN8W^P@7;et^w{hFe~Y1|xDZm4G6xg7N9_T*pv>UE03-=Y%z!j;o0Si3r=vEZ3GrXN z3QQ9GKaexn%>T*E4212ip-Wl}gGX2z(1J93XfS}uE}!a;GgtF>>`c54yc7mcz_(tQl;m0A20EK5(Xej+~L=MeOnX8i$n zx^%;)+y)C9T}UC^bN{j^jhT<`#w52uj3#Q3>pu5h?#V}2$O(5Y+5KE&M5f#`l%AXq zj)qU}=VC0rFjH3cO0toa@T)?C}@s)QP>0O9odi>bY+2w+B&8=LiC=vx<{mx*X?SXrc>QgND=^g*Fy3fxtls+ z&dp&0P62)Luw$0n0*$WV7V-o*dU{$-Xj0r-ub>?LdaQ?8d|m!%Gno3NSP*;jqTEdL zvzw+E=|RT*(TTKxkq!h&jP@LQ%oesBeW;KimtLf1ZoZW?Pprdy)7!iDzQN=W7)&N= zJOYEC;buA*RL#@9q{Fx7%Z8|mEdB^ND*iiPQzN{*jtej=U_ClX$CgZjZ=VnR{Z4~X zftv)JZnIGGZIRJ2o0;g3!R`ei1s1iXr^zosr4PgMhb#EN76Rx>^mi5> zya=lhk3Y~wcnM~T2^xHAeYVoY4-@1O11o&Wj*?GAKB?Bz;k317YMt zqiM6)=c8)9@L??^Nn8d=jaE78y-YI++(VUq9c>6jDk&`30_?nNowV3T`h=%8aG{e= z!{d$WI;b^ee(_u=V5gxUTL>ef!}VFP#E_=VMSc;64Gfe{S#-CnKMhX`I(g_TPm`NM z;|4frTk^i|2nLGTd5E-v%lgR&`}1J0d>S?oZJkQ3hm$&dTPm4&OU3eC{otltr1P`6 zH&qPOfIH~!_E(0?MUH>=e}C$_`zd)No{~@K{_U?%ncaMxi(LO~7N}m&iN(85EKKjd zq=JYFYo^cHpy)-W>`aN1xl5l531>nh*$W~c?@IPIaV#>NtgeE%0J{*X$o^$?dk%>=+gxy2bQ<8m^NXbkpEn&)``9Vq=_=j-^ z6L=d)tTgmy970X152$QD4U0_S1p~9sfy;Q+c$zFQyZQ)!2;Df!MW!@{;Uz7d39v?z z$DD@Z%tbQyGfmHCK*$}YVD8{b919S7(ANWTmE(IVt}U=IQu_ff72ofC2?8D0n@C&T z46CD5IrHIgL?Xc@;@XBQ0oUb6B+-|rLH_a@Xwk(MTx(Vuhd=5CR`v}97C|RdL%FgRw76Rn!3U9r|d=ZN9sz4NA~h1;522?{p7<#M*w0; zl|{7GKlk^Mmd~@mwnXOwoU@H|_P^6{5Ly&Ajt+x2R6G;9U)$Aqe^?~=4LgQ7CeB4( z-2d?(^Mq11L6R2uXSyky`^1ZftVt@!jI@D#nX^ln@g^6^P1(;?ug6gO2xYGW{-?h~ z$YvqDp|9HyRM7F=Wp$<5lKUwQ?v#ynDr+-|>XRgtHXYqd0|Ko%q_Q#~Qku!YKA&o? zYEop{iyqO=L*3I5U}*lKwOJ|ra^q#v(XY+vBblFbi1W%u53JRjd; zgK=v)1^Yrrf{ea{mTAE!Gclmcfj)PdM5BAhuCO}SC1)~Hm{TFlup1UTUGIozf`5G|FNkbF6JP@ z1nqS%bAe`sv+03nrmQb{_mjv}?Ti(*yd* z-Osg%9FPlr+-u!icY7Mm;7#d&dDE_bAZ)s&)2GQ(ebJ_2xQCjh1mqVQJt(u%TZa)C zCN{yd@Hb+MpR?b`j5fw*--Rb{_;a+0Z(u)Id{8$PV!W+d^d^<#?aKG9fE;f`cqS+x zH^}E{@^9pueNa`|PbwSF>j8L&I6i0a`4;JQ#bVVA#1(>T{vqh7hJjVaWmC$TM0~D_ zQZPRagK6fopHFoY{2{OBESDQz@A1Nyvy#IG#L}235jjY z@H{&+bcmfYc=7f`2tLN}Y%R2K$2`ir&_cnx6!NtTC|Rl$J~Zo3PSB zU3cQ$fWM46`UX+-(c4GJ$GuW&1Ga|789GeZKAP>GJtbccl_vuAnl_7%XpX_=g-J+u zKYW9Xz>^d4q|p0A=MZQO z*uPO*qMb15p$dj3vf5pR1XN+Fy9%k7>5JuE@x2s&n{{d$Hp0m1ZV#GkrtQTB4YM+I zA5a++e!ZNSFJ)PHf1<;R4g)d@VXzaf+37Z(iNZr2R60Gv?l4i4J$Y9;l)ou>RY6J-n*A4bv4O@*&cDiUraWPxq`B z{VeH~D~yME$vy6wx8O_dyQMa#@!q%Q9ZfJ|1tSQX_%ZOy-)(PJSOQz+lgBe37@Jw4}*;{g~p1|&0=y8 z4|JzxC~`4PF^&;02)Yt3BIFohdg(lMT!MvH7*&8Hazn51SP9&%i@aX(8mD~UYopg0 zmj1mi)Ru6Ae71Aj5o@80TaW+G3g4D+li2M-#Aew0Zx_aFhSBgOKbm2p72Wc2iYA#&_6Gi*l<~4N>~>C$PT9^i%eTp2lz*(SDAK*I%bu3gYD}m9Xq}#r zKPpd_FOhp%8!EdarERz@J&C_V(!J6Tq!rSQQrh~z{;iN^vad*AlD;5)MfyDc@`Z*i zTujn3uO;#&UUR%>OMgT$592z+PLN$!-Bt}&k5MQ4R-)_9u;IQYpAx~fg^Q5B!hI-2 zS-1=>Tl9oDdmIfByLCfw)pSJ20tQP-WGSM&B}=-7tP_@7xJ2(c>qaB+v`BjUh20id z7W=MaV&4TXsl)17?@(KPDvpx1{lGf|lB=v&4LsDN2oUux0%tKvlCDc@AG~8S-r-$S ziV2-;+JOI8#m7hB3Z}-CS;|+9R?#QUDyrr0hbQM8z9o5O0y|Rl0=CgK={`r*s3W25 ztw~bDono18pEyH!p_Gd-9wQeV52k2ukY|c6>8Z;Z(_ZblqJeh-I91&|z33%J|X1 z_X09;^ijYiddDnSnv+X^A0_R=sB%shhm8st^WYYSOS%rP@u^^=kC3PP)s-ukI&(kE z0q2I!+#|eJ&JCJS=80OD0L_kB~(sn-+E~Gd&-z+Y)Vgx?|sRo#m;Hlo*|5 zPRAhpf1(3Cq-B=ymcR`f^=V(SX=2BRu-pIecCzHd+iHLJ2zfHfF`sEGyY}#zIo#t$Ve!7y|0ayzYL(mkSn+U zXeRT})XO)X5S7VH;>4~e*U^w6r=cFDHD+Tl)G#{Lm3{$F$gw6}rT_DE`j0OPH*L=R z;?56i*|GCXFF=N~S|UZLyRc=+rceGTYv8&k{x7<|1TLzo{r}#X3(Os65SJ7Yby!qX zGPVqr6cKNrrf6oSR=CwrW@zT?Rx_fRl@6Hs8{8tdsElDz91%U2 zb^hOTM|-Q^`=8I}&bjB@bI(2ddCqg5=ljT!J}kA6|C8F9$ElfEa-AM0x9)!=_r;$q zLt1R##3qceKNoR9ia6iJu!nlC>#?G<_ zO2-=J68-RB9|=P(1O-J%?;Fz;n1@S1@Tx~P1vE;alF@d=p>v_fI-bA2j!w9%S@DQa(yjz@0$bU7|0vkO7;(-Td`$Z`JSdO&p`V zbwPQn`nI$3*}Lbcv2DIl%@9T;-_&zJVPiE`etSO5m9pk}wT;DMD8J|EOKs?JDt3Pf z0$RQ)Dn(aw1Ozl9AZgE~`6IlwStX&yy=5<-2S&ej{;6C)m3`Clmy9ETS@lvvka0Kp zZIjrs)7INa--v;ML9s`0N9yq{M3V_?FvBncP53@q62uRu`(q-=)P(8B^oX^)av8U|AL4SMyHGE3v(>HerED>~jZ&Nh?VE1x#Gl947%V#ke z5JzucbYy``GhKp3zbA=|`CB4GP-C6`*0c+7^27QJZ@>QutI2=%ndh2V!hg@I14ls| z`v{xZjXL!1GfJG%5Z>a_R-z{|kef>;8VdwPpVH-z6Th{JVXMr*V;C#@3s2=7Rk!+P zoRK?W0UK>(U3GK<23jMk^#Alz1Dc4A$TX+w!EvN3@_H+~NF2DPv|nB7gc zk{2YKe4BLO&M_$L;r3sWf0oCD_~-vDM}n;6?PbYiR2C-o)Y(o0#ls(byBt{skYJQq zPjaMLk_f3bMigz1*4-Bn9$vb<{>$Y^1wbjhhewm}sB`pPt1oD;VtN(*F1!@jH6cv* zAQqUC@xS$eGEi_SJ9gt0$;2Dr97CO`^CROzBfs%1z0;`MvQd;jRkC;4Ozc@=Z@0%4 zOS*4`p$D7Hs^y)0HiA_!ATy$c`DZGA9{wSUf2!i=;15&$FXb~8ma4w2!k5Ib0dkSn zfQJG(_GI?{2<7>Y%5#4-2z!1_5h~*C%ajsIkq{x*4K8`x$?=%yy&erLWSp#+wT50Cm2;?Jg zuhXY8J^|#tR=Z|n`g%>*E7FR!mz9^PG_?wRI`Q{wpw%ayaw`XpcO?Wx(v1(ugU zX{I#lK_EmgHwSV7&=-a7ZH#$IOb0@@i9Ml?+T|Naq!!ZmAQi>iyR2kyvUhITSeO4< zmP3A)TiW}sXTD7DSH1jzYirEgXLNx~z*wZ}<;BPe4zi|e<&{xZ>Ht0Dps(by{=EJE z7|^egk!;fB(yqefIh!W6<+qFAvHKTMRl6)Txfm zw;(Rm_6tg~L3z%R75KO0=V1J@k8nVt_|-w$z7b>lUZ&@pP;DU~CD4DfRx+t7-k!12 zdtneP?N*gM8TBX0d*6zE`m8}`Xrn(OI7nIP*_!2p1l4vED1tUxf{u9#TKvV|irqra zL0Ff0xzJOx5Xv5ZSMt8m7p(EEB^a(iZ|ChxSI#r;155pqH{uZSJMm?A-hR}~b_v)& zki_p`q~tdF@;k9>{1K{Z)MPrxcFhV#)@o9%baj&^leNdS6}nAcQkQ*b5d%NWt@Z`= zb?%~9`$SFZQMw-I6M{jLdC{xWbV!In)RedHPA2kqVs9kgbGz8L<7HTXU^%QmjOI}0 zIV+jE9UmuT`F63Z`)6p7HhT6j>WX}~U3^A&kzR#~gMgivX>=p0*e-VJcac`K2J8$- zQRw!_Ua1d^y;Cn^FUMY7e|WzUHMN;d8iUQG$M+ES@LLtu-FL?z=@Y+;bW>ZT@us{o zMW4ocFJ~VCP;^MLEz+fN;Dhw~*eOPTAz2yx_jzsxW_&)B>&x4pGIx^sp0e%9CIwvq z+m|aqa%DZJ4P5?7@|?&a%rukVlmwV&3T0F6k&sCy(Du%Cx|BK`Ly$dPP}jLrayuF` zqBYlQvDK;_wK!%;jFq01*|W~_m@!KK@j)j}Yocu9(?+`>`7!@1d8`)BUReqo-K-Ze zVzH6#QQm4Po+O)mlm(D=hllX`1fgqy{%@mo#m-JrQ_SWGHchqBndsCo4GRl*EdI@6 z=boaC{;Y&w!TUN;*c_(ki4N!5_4D!(N|&}SpKtWWwx*39MJ(29S=_TUO7}S8$>nO} zaI$q5L^F0j{_^*K`*N1@g)Qt0k?h+U$OFse1|>C?JGI@2!PrLEJbrt1afC6nJIl*8 zg)YWPkP^Zw;ViX24*Q_k#UJxPa2ri34qL3;ndm!6blU%@%_nsqJM3+}T)1VOaOj4MwC%=` zHAL?kS^GWN7M4<88CzjRL$JkOA=ev*7#A3!7viZ)^;D*j0V{Oro|snGDqXrKiov=x zlcMdq#~Y$+AJM1w@PipQ;3&8ON7XBULCx}}Et+TaUB~qu+TgOs-8iKO*U$Z?ntZ(n zEAzd=2xGi&DbT!}vyH8g^IL$1b=K-dYEbI|U_@_!J00T|KjAh&)H4O5`SsF-SnpbvO4V35pXqkra1cE6xM z4{N7|ANZ!RHmWLcPMWt1oQXZlwm^~7-7#Qj_eYJw8zS=+~rh zuju<)PsQ_j!DD_^B&5mg4-_h4c>&|y{(w~tGJ*xl?iQoQxe+(_VOu95O-)|Jt3{IuIS)@S zsT2%_|Hhlz!Uz@g)JP|>(h%~C9HB@;toxY6=HRTi3~1mi*C)xlIpQ-f!*uTBp13m~ zirrppu4A?B2ZWW8*uLp}{FLs0Ox};~!usTs{q;aL!}p(OWtB2?)d+B9Jk=wVSz;x5 zCRgmK?IkmshqL>AOeW{ThUo{is)m?z#Q~-mY@QewwT%wLrX(+f4`UmuosiBLGUpwL zCbR8CUdRo3nISdW=u_V|`{LA@14q&u3B6GW{UFe&k7%&6*&5bxW)CwF zcnw%g<5nKSQq9?CLisHCafUu_&b$4q8~`8wAE&tVaf-`VvJ~4Dz7GMp2Zy1l--R(c z7RPLr0L_+&qu8x^+wV_PW64PgGP14or%H`jK#MzQeBMi#9(|172@z~z^f^ik96`A= zjj%WHKDO=e&rD#mkv}7p8AZ`oS2E6btirb|qd$XWXrtLh3Snb>0|&&VFkY>~-f?Kd z&$~cxn0${UjA&T>(ujmM`cuK*qn&;nZ3~O`w^$nyYZ~h1sSKapFcgn!ZJ$#7$dTP~ z^Hz{O&*!m5m0Wz6JA{z}wC=l*OBVguUN znFhsv&*%iG90$0RbMy=D;GTNPCGcstrJ9 zmGKgJcc0j$`|;sGiH3Jg$T!jYl%6-)R+hb=GTo0~OSbM4eY>2Y2}*>`(SKfdelikU zu{83_KJodk&-!x!Mf?fU^ZKtD%uj!uc5vi0{f0cVU+fijhIWye7*zXA17vdDp`JDX zcmv1{(1Vg4n)`0*u|Va-EATIIT*h{5Hu(fE0%`Y8c>rGIA@j~2PIE9BBWE%I@V>87 zi}15V%Vegk#=d)op2Ml}5J)+^=NJfkYs<@CL=BBGcmBH5mYed#6l~*%{|H#y<`4Xg zn;?&e?YTK!^4!=%nvQjx$&Y{5_0v~74eXHkn~DD3>}O1YwRj9Fv*(srMF@}gKSMXk zjI|JDznT1mPXK#K;1i^Ubjw{j$336-UkcH$LD+3s(a-yB_Y zow4xL;EA457PD4bcK8&ic}!}CFi3rS0-*EV#>IcK)bFCdarTibpv9%c55v;bO7oR3 z|EfGYk?fDOc)v4{b7aqUA7=kM5aS`$^+A-68X{ogfSI6)#c8nRtpGZ7@7c6c#-Ua?6JTItWdVJ3kI|es-Y$#ys&j#eH1?Y?&GQNTW6_tBGk@L6&<57raPLm;2$sVZaUz;gHKA^9^7=(D;E z&rQhD@DeEe#mFM}&29MFZ{rwL*(X>mhc)bGNrZ5|r{r?}cWT3>w5yrM$n-PMCHGEuckhH>-X8(^y`~2l-;p5y5c^I}@AK|0bUC3+rEdh<$91mDkW`puVN_r+#oU0_u)`(IHk7#HOFFPcemSGaaEjd1PH zJ@^&yBQb_2Ru8y-;Sg$M{iBm7*S8${Qk<^;P4pCK+i<#aV{&xQGXIK?^pGKQcj2nE z(8m5vfazVxkGbLKMh8u9(S@6c`_~cn2xcM6A^GyQ3uMaFxX1f~6%C;C3|lj@J1t}8 zSXdjCK*Wi)5n~q&Yf$ezg?)RwBJt^%66y(Hh>2Ym$Ea~yJTrj}3)t~+%rqJjlt#ru zlwxMXVy*cAxJOTzeb;MjG4irjoBuWa3#CX$Ym?Az+e^Mw3_PM1y zBBbdEIo;-0Ac_HPGlr#N?=kiC}OofPx+r)1mjr@K*0nAh3LHS?w+s_(xtG&*CViI>NA0f>JEM%mTaC8xmc_|#nR=OaZD@I=O z!UjA)7J^->CMIjkq->o`QpO!a0I=H$8c}2$^7{P%Dl~JX0tA$>!OwA8#Pb zaCpEN55pR!?Rwv2<>03ujKEv?jmPqO>w##X8?(q)v=4iFC< zUi7|^@$UBHpK4cUuvM#EXZZ2SDeMHk6JyVi$*(9}D4oc~2 z_Y^&?N3mpWRmQ`AARU)oz!uZh5Q%-x>Zuf9dx0+9C!>U#6>fjHmGJ}1s0+r^hYjhw zFyoLv3dH_X3a~4-=X#}Q<$s3+eNfp91_eVAiOxr+f^nkzsr*^+a%A%D0`~tFGSxog zCVkm~2}*3mSp_nd;^wz84pRlUI3}NFIn+|%e$t~v3>?JFAuY7kq>_{v_{}h+z-9lgsWXnS zbes;$P}jCIuqb&-u3FbhXXpE}q5=7k&0+y4)U^BzoJD_N^T7u*VEmC))CBA=f=gLA zW_QC|0O$!W9oH~z_)m}A=dqC2Z3&pQJ3|sZ{+hsr!~K?ntm6%6?eQ+$sKAQ?x1&wq zUdPq@s=$S|2%IaMg^&gu{=yzoCQP^bnXEfh~ zFU;GQF%>wA8FKBa66lzv$;UunaCTx&1Jjk!g`4rLsy&l2{I>D3T!f7(ukip@$Z8GO z`?6df0*TatfT8f*abM7s(%X$=M?Qeb`f|KcN^jzgwD#+A-64>B928|Ky{v?AUVR@T zlCDEs?&kmqKQ8M+k5ES|LP*>(v1gxBdZ2Mw97;bw5KVX<_90Z8JQMheqco<;S(wIa zCDfaIc}#o`7>y^IvS2)XW&&HA=4P`ZnV?aBSx!+hv9R$tsQ=^gn(59$R<<|`X=+GB zoZEM+@5g3*1?}O$sY-i zDv#6Ure^n1eQ|=MmJHo5!)$mjMYNMeV4ZJ4lj#3P!ta$_Ndx-C#-9Yv16Ny;3%`@Q$n+WbIApc1Mfsg7$kj+_F)Ej_+1V< zqb&-U`lj0<{c~}^XXucB4NS4;t$e1prp@G9A@KVo!*@pSc}!ea(ZFNH*k}@;@cv4kR^~VSV&C!1*&-*3CJ-V_X1m z$ppDw$yX;t|0zGx2F1#AoptvzmxnhNC-|v%@L_S%?gb0z`l=8q!7o-?K+~&KyM{x= z6-UgiI0(d~|E?SX`CITWVU9_?Gr?~GT~f7s89!wAf-^RDzxg-feNr6kafU8y2{fvA zhDwF7KGkdpa$sEU6eQdtib&!3)~FS{*>tJ zb%d4`HPCa4MDc^NL5YD1)!7@hI!762m&R6RT$ok-5Y;(CR z7ze`B?PbCE_TaW;bc8G`1BeTTmFJcwVm~Dg9OZ@6q99Ke=AhvYpdY5jE1RdKzR>4c z?}s;EZF|?&1N~vQtp~IRqMfUhJk$1LemD3BLp*?W)wwcBIt?)WoAjM#vgNes-P?Lb z;FjT%P#7bw&bZ$}1uhv^P(pNSfy5lRyt<6R!4=vx!CNQ7n!5vX_PaJ-pK$Qi9 zSiMOvHInGFVsI$*+FMvPx~8y-+~3GBW6HtV`PR&Y!3#l8z+PSMHgpDGrK$@W$+u_4 z=#UM*uIW!IRcK|)2r`s1%;+bL1{>ZLih-IGo}9uu8jLqj(Ja#C94uZR!9q6toY+@j zDf11Dzm<7yn&JZZMWE4VimF&F$yS?Y> z@K(O!Imu;XAWVZEfvx}`6*7(hh8K3o;L6ZVashc(-%RZI298;~{3K2tTS(u*_)E1i z&f{|uJ_ds9Jix-X+Jtn#MrGWfZjMZw!6*VaC8dj7@Zy*}ItjgVSi=%a{(g<(#%Y% zzZAA%xjx7K6aa8{o^Ed@@t4GKjPr&zvicINB%G%uP2|EQ@N>`8-A&}tC2;{in7ngY z>@OA00Y?XP!YOPWPJ#`|lm zWZCx;#A3=Inm}$`#&pEAWQq2Q7#d%KlU)WUs<4gMq9Fq)f2QU4upI6x|NPZ=VJqtXvY;6K|q9QqR*0jKC|R*VCtAIRWORk-xoW zAp=|J;2Ago(-?bXFs0V9#tCwm=V1U1_1Kh@@DeGzB4(gw3t?N~su+xt!!pyht75!c z0aO}U%{E?zO`OfO0#|`?k?;T$XuZHax{vXJYZmU4kKj5ca0BiMT+3a7TZAjHSm0LX z3*2VhPb(6*6u7H!O}-;=_J@BvHQpNS`K;~0a zBBS1-$k#uM<2~Ln&M=OSDSLIYF%RkJ1p1OY zh~v8Wto|rWp)LJT#0lvoY}}g z`V`Y3t}oy{5`*Pf(rkxzdW{UHwfMN3~CF6mMA^IAmMM*S4W zM99t$0e@<~W_+mgzlz;@*mOIcc$}WGl!vb-P#YieGq-~VDJdHcg@ZtBU*DC7OJ}iZW%ng8S{+YCI&a!d=$G zq^KFdJ^?V7QWC>3B>YO{D$@QBarZE^7BrR&}5jP67HR~DnMqhNp zc!XXe4{wXZOnLNVlX_1787{N9Uj3zsHdl0&gEn`G(b#+U2;6a8t`*pQ|!~11%H@6{58X*THFg4~A^ds2fN<4RwzIXpJ+P#k|flgP*25F_hy zbItg`$US}9I@ri7+`svRPXclEFiKF2Yu0zJtrWMf9?u6vJ-Q+VtwWO!kEP@ z{sMp_7=&Fz8B^=YZ41s_3<(!SfpWwN3Oy5>7-zf=ob|bL9{9X7i+d)(+G*4fCuFaz_DUtO{e`boPh%XU#U_p!Pz2m-Gdjdk z=qF+yvMHaoGzaG%e7r0Ak$xZ_gkHJx2?)=HRboG%3y8x7lCtYKF>>F(4RM)CF*fgw zkx5aNXc%Y#&SV`c!qOFix~iy4i$ST`OQ{C6M+aQpyYsB^eXL0HQ7&7z>O=>ZC&6>>H#-38GO`j16{j&S#P< z2IEv+*+$ss<$_)*14TyG){1X==hFdA-mnP*irPbM6acz{@eMT3uiJ>n9ca6qqifs9 zVCUU`+Q^%C#Hax1!QhxI%3f@COJ|hGY3San0E^9e220G2P!S#7O3vO9lT7`vwTwe~ ze{4C4ULGj1%@xl4?J8gcsWm64xtUFPqtU-hp=-!sK1%^~$Tp~<5ZP8iMwr?D4Mv}O zu9@|%JUYIG!K@Ea!m?X9;PJf#o(J35o}j&&-#412A-R7|MI`^O*d7LiI)bLVEB5eC zon1;#z`(&EeC9}-@HH@}pg;}ywnpMwheOnJbYrU5e8b+O&^Dmbcbd+R+ddxaPtHjPYB6%ftQe80OJvfWU9C=)*-L40pkjcYFHE9G&C_ zZW(9)4Ev0kt(-p$Scks<4&!YuH-nPtg+zMhGU+-x<_)6>>XQ%;l6i=_Y0=~Y_Tel9tfv7{_H6Tv zL?$c{J@QY_8wQm0PgLZlkwFPyG?K6FqJQ5aOyy1zSvH4A!Y*deb&AYX$BSuO(-pZQ zB(vMpm=kgZskLMKQxVc(Q^$llW43WXVW0gQpeW(KUj^L<&R%WSpciViM?s3@N*|0q z4H$o>x%w%riRj+)d5-hjVLVf-;o0iQvc#=FPCK?79a(=vwK?0E1|lgHEYAwxQ@Ihw zb2t`%RVt$Qnuz>ruzJ&s2g&MBaCeHVyD#>C<1Bcw!1Bx}rk^2)o*goBM?-1-1T3i+ z)8$GC2PU+p!avaesrT`e?^ zbgLIfs)m7|ST6>uOQBx6wqER_TG~Rk*NZ)-RD`s*MMyPJB7E1@VN?gmh_JNxG#YT$ zah6_fbd^>?>%SV?s#`X<-e%l0#oDv5?=#aTpo(;;qP5MaDzTI8_;wsFqy6naV{`R0 z>G41`wEMQPD!0OTh#p7&V9#Q?N=CR ztf76I$i@ed==S(p2W!6Rpid&Rh9dU%yyX|#W=Aue%v5&+kR{k;o z(+SdXo9Dsg93KWilO}BDas2!q>HbjcGH9klmE&2=m3SUpsXXQ(V9TYsZdM_R-XSQ@ zf)8>5ALn!jvvh4$FsD(TImo*Y#c>1k=&sh-+_!Ox8pL~I4bn4)hk<)$pw$h0^I)kj zB)BfpoL1iO$hJ~m?P&!6e1n73KZH$1gUmKx!H_HcxYZ@ShBkq=IBnC9Vs9-0V&M{S zyGsEJ!S;U_>HF~IV>)GK2yC{#;E8%;8n{T`YE@@?NqcOaFFU7+&vTxVTrtp_WzOFv z)iqU<3IuKANvu3>k`eBwZOlRmSO(;WN8+%c>i!EYYh4beXc28k8mTzwjY6=BPvaDH zMxuYB>b@faxq519*U84H+}kuw_DkgaCv<%&!7uUUuC)nl97(Omb_v|_E56RDqu_*7Z{C0pc2fK zsFoeSMEEKpon2-9E5m;W5LQc}NjcSmuf!3!-#Yv^u%&2!SiHXAT<9(U| zJM8LB?GujeTP_LxeXIf+=Nwtygd@lzYHAVEjkyzZ4aOq+ePf4MA!AX@W$2Tu!KCv~ zD576A0-QGGG*04g+CJsf>Bs0KP~tz8sndnvA_&>K`Quq|hIGN^40)yHjP35YR>!S$ zCy~$-L_#MsJJTtbBZH4s3vWdw+5ulR3otRgN3gygIMZ4U@BthiPImz)z_*D846-j; zp9ZUf0qUNi6|iaRnh9QU0_LUVfpHANBr6e^K)ue;i*00CGp5lXt6RUPt=+)F=oZJI zna6EvMep2ej3lI-g_BVlVoH>3abR5{)d zZTD2IfcxYPH>7&W#{R7~S811R5{hQU31ZO(fm;Z7)ds=DCBb7q=pucL^Q)d{`o7kc zi513!bY2?+RxyAUWZ72l^0#CWl%?zh@58pte{bauq_+V+HcS*>^9G zRY;XW+Ovgq4@fjG7cxTqY%i)pY{ab<;_I&S)#*AZi3Z(O11;|uNKQR6p#nCXKCOhV zY*ME~X=;<0d7q|%ZL|m`K%5e|3ClBaS~F?+DPu|QPjPB6p){M$0?FYAbWu=l{3cqwi5<68{;Jn=hv=VGS<^rFG0HarM#|ExXck5N0mb@jgeOMQ;6i$;rTE*!dyDwL#7t+91 zvvdynw5*_O$SZB)c;Pq=XeN8wM6V87piwc3@VCY&%;XmOYcsjlCid@^(RBtiBYi_* zW%39$HVKFX6geK`kxUE@u-lJNsfkQ>Kt`wpFd-Qjy}R>y-<#E5{@3xXi?ny^WZ;E) z`RkR&J<;mAnU8c$b4gKI+hYbexYq?BBr#SNSCd;!OPXUrzZ5}rQLl7>f#?9SU|5_1 zB#|E2hedQxvpW4SUD}8vRn*~k%`ON%LzgxSQ8-i7aR=!x%tlTYP~cw`f1zbpW$(Xy zr&_+LRKv6&iURS__EPGsmu3~wlno=aPh-p*n>)l!fO04sCa;6j`*EeSxsZXl!H>fy zAe=Q>le`!Q=ksxVy!l-hZW`QG=LN1V6=X3EpJw2C`|*{8gmoe`QeK5IXoUsP2cW<%VjKS?q#cTRkxpqM z243rJ@&UbEfu!yMB82mu6{t>cUv`F`Xa>?7hL5-Od9H&V0H-NQiBs}8&Rxtc)p#@N z@i*Oivusp=RqzNC`$hWUUthb>%y?R3M>7h4X-qfci(|gZ@y5mr#m^0>%PLI`DuCmn43Q;$%V$ zD3c6!)g}Zb(J!iDd2!Z9F;`_{NP4uJHHogQJ}Db{&cLH48yY#^c*uVz(KoBeNmuP2 z@DYA!_R5|48B?d2nJi?|I4>+bNi@EStZ~!M^-rQ5s<`{E?vpXEsG8Y1B4>YQ`PEUA zK{$=TcH;!SLb_|TT|AG5UPM3So;hf(NGxPx12GzHsP-bxKsMSAVOAk#4VrKc*^0=6 z-lN;^ae)m0S>x>b!aeW^ylVh;-=u8Q7AVYJ1D^=#cjQ7s<=+O?x=FuES0%sO1^5ln`(TMs{W$e@GF0eT0+jaYeUq9)IwU_ zwO!GQ?HghKBcPD#v7;=b*IL{HA!Kg9Vm9OsuTSwm{^&npf6R(Zz*YiF`eS}^eO?0F z3jIVKZ4Yfw9SJ*W`$avmWP_3Kb;wp~JOD*Nm=`&!0xi@MBix_tp?mlYG3m5lK}%&< zTYqpx)##u626i&NP4TP#@^5PU90cSjaG5|FDKXZyK_)5w*<2Az<9m=8Isnr=ui5&e zZ$_hWi|Gm39A_TeAMY#%orsSft$TS`vbq>GIecn zk>p%$rdyz<1axc)6LXq}6^!lFPvh)Li%$)fPui}}!SwY)g(40Xm+ga@o$>yEr=<=d zqp!_B(NA*QVlWC}VusXUUbwa@fh(ssnl^f9J9PtyW6Ks>FOY$W#>2ot50R>nvtEgZ z=^pZohxWOCr)l?=7vfmK7emuHPIe0fajxX13~MJZt*vd6E2mt^fl2M=@nmf%G5aE0AeD07yX=Cqnuvy5qHSIUch1 zy^;>lp&-uOca8!}E+~h4rk^$Mh0=T&RC%_5W;%Ye9f0yGXULb_Q(nRRwjQ8NWl%3* zBg{Md0O{3E+hqohxSQS63+PgZ4V6(s$G3hD=EN0SKo+_quG?Q@8jb`?D%`Bq0vEES z*=O3{n1#ie!!0bpEfqXKg^;i@c)J~H`Qeo)IeV} z1cNa}8aV^l$W?OGX}Y-3EuaC*BMI`h&d-i_d7Yc;Q{@T}u{*Xn%KomuA&m z{SSFPRBP)yoT3}f?P}@OJRnE11Hds5bo$wB=tRu(cv_ZJLP-kg~1HWFixu4~W(b|1# zk4=4)IRISD5sAm&Ar+&woh`G*X&0yw`^_55jR{(ft14x@rE;>?Tcx@&&Z3&CEf<8h z>9tzRtv9r7dLfaP-?3D@tNo0}ZI3&ax$kMOX>c1}O~x$JhO@wGvT_k-%tY#1O?E8O z&Jm1s$35b;SX-`2dd5<}SR3JnpqN_AfaO?4al5_7@^-RzzNczRwdK}&ZM0f7;ZKX- zM(s60b?8@1+a|56i&lby!)M^huDVVmK5Dbb5EzYYb}u5(c_q-$Is*>9 z=C_q$c6}b5S-z#_0&bCy+O*qz6X> zXrCFFK=bZ~K}rblLuKJ$NhMI-ow+*%?ljIQhTc?jo(Ba7y(KA?_XA zT&H0<|7gDDVubrujcFRKuSql}83#+#XkE=tV~%oHRa0%WD|feR`X&Y^vZuFd5)+e@ zyK6N&6LXZi%Qe-BcHC`{1MM4e8J;x^oJP;qWR1K~_OdK=8w|xq!JUtsMoVj8WbX#s zrE?`}=_0SedG*uwCQF}a_Y5~-D)qT%IUeU8)Y0Vm8qRqRew^bnM)TFO7{<(l{mC>B z`>RbZIl*88+Nb^fxo7x)W5g;ktpDHV5z6zNe>^w*?fpRZ+@&}L5lF%t?(;2`uend~ z7ADi8dzQ#W?rA)3AJq}VGWSlTYO(ufcsJG&JPEZFEODQ~9$W9S$A@wE_FW>G+=DD0 zAG)t(Pd45mO=kC@@wZgqVOn8}kR*@`= z`x0Ry{qdfqN1l6%8*VjsEc;5_d-J%RQ){_V>OQH5dIF6i=YMnWZ%O#oeIGAOpp$Az z=il59;I5&@a^W}k8!S*;L-zim1n#IN2n@2Uzs>S6fgY|RQl;`_T9u`(l0_d+=iei@ zst`DydfszJKU&SAkEgxs$iiCpH*q(rj#SjTdl|;lRreTMtG89X1B^w#@l;#K1>P%D z?+B5`(~mH*-Ej{<{Gd7#b;rGv_jqckW^@VC~p<2z&!ZlY-=H7AdftdU1 zND5*O9Z$E{1?KXLg8QnhoWYRbS!^&eX0TnQ<_e0`Ts_=MTx@(f=mm!gWMVg?5aolI zGm0#~-*F$K6XI#~Jxge#`$83NwRM&~&F)@2ZWrFQoNjT42wyy{x?{1oy3bYPwqGro z!Rw-Mr>Z5}d0n7KJiSxn=?6NsYdo#Q3c%}75Aj%dEGcSTa6472E=&CBqu2p&umFqq~6=ye)!>jed!gF-SJxl#+{ZN(be1nQJ_aFm5 z*Kb5{{auUobA5nX<xuk=fe=p^sqV0=ARE_K5>Nse1QfC@Pas3v#)HUXjV07X1b7vvf(dtMn{gRBaiW zr(eRG*3z*hnuA?|Jg}C=IkN7%s3%89)ne*HSBN<1iP@x+)E&=;I9viF`1-|?RMZ@jKbV&jn*=NnP%iHrzJRwg+}e1Sf|1KD%* z#mS=qS(xr1$pv~TU@eU-!BzrfgzIL;`3uFI2|*kOWdx|&V#~v&9t1y|Jv+|vWJRI=+3sdKrtzuR zK|pLzr$4l*c5?p1QR%@6jG^^_Tq)EKahY(J=K{%7Mf%8R!gy{ou3fnHAT;TqE6VW{ zh}*H?yF$9&IySSBBsH(crf z7)gVa_rh&k!=3*o_5=N$9rNcW6|+Ppw~?S?y|+i&-@;k{iW(A7LrAx004(z1Q0t0sand1JVWjIla*eAs_IE*ecA~hv#u6 zNobZ%k_!rSvs&=q2=Lhd#y;_n*!}YU9ry0v;%2v!j}Gg-LO0UgV6;B@US?}Qd@uO% z_qeBeCNnz5-rw{A9^C6`2us+HwoSwYP`~Gh14=Ov$7)}r0HFr%a zzFK1$TB0Az^XtjlQhk?!^B~kcX!M_x1C3s}gP~x{`S%AZsK*3oDQrt;C@^~%6#SFE_oFAu>J%RDfeqy#Imh%vg?TtuBK61g@wj`hiAcv0hPc&a^>NHZ^XMOq zWbg@ntZ5$osgb2#UREwga7U5T&egmDa$7mRo0tI1rsyb$*ZM1Gs!`HZK;89;3sm5y z)RLBFN=l{27dulktFSe<)sHsO>&%cFd)ocTIGy4H&#$h9V zNw%n$mEV;8I2?Jnl1ZKNDQ zZ^=)qiIP6GdB(XKJeAOJIi@pv3E3fcaT%^e}`k3*snXRa-rCP6(Wr7zDF z;97z!9N#d))w<$l5^g;ES#F)wcjCS0(XV7RdM(%gb+EKtATYOGVI(eWA-dE0C}9xw zZYA-j^|Fveuc5il=%;i_f)yPu7$QyvaO0HN5Vk5fqaTYn3!91Vtlry{1l5lxaZ1W~ zgIh%;@)`L!pG&GZgOd$C2%&=>ht5Ul1KZ7N)$R;wfXxdHwO9^|3sast8|rn$_}wN%LK6V?>Vgoxp|BkLt+Yv-$wfL0~cI zQ-Tp?eqCN=@*m{)v-;6b_2M~eZ=TD6TL5=G+-1E<^f~=BfSkN4lWphp{Z!X(kqhVa zb3HzQDR%)p;y~jEw9r9D{iqKxh0$5}Y_|AYJQs^=0516^&u#KYx&dfqOv^4HIzDu; zSvOF6Y7Cos7tp62On-{cG$e4jQ*+y+2HGoS45N|v9P~{GXHbKbU4XMx-DvR8LKwk< z^DKafd_ddF?vfkKMe-0~6T2FZRCE4SwoUlx7<_aSKAMF4*KZQn^Lj&v59nxUGt9&J zVxQ|Q+c6Fjab6!JETl7JVmz;(D};frA=l39dxVD3Ep=xg^OlG0&19ruMW?O6RgTNk zkLMO5eJAb2Fiw(Q=ywB(9r`Sv1#~7R-Pqg(bY~muNS7c77*WFYUO+8vr1FA3#SjMK zHX`?>*bp2ZFNz7HU)0SoNJzob}D5%Bl}w1#2aqW%^FI)3uVo zGJOx+ecwz*mFc59Eu_5xA#oWhc1&JlMD9Xb-b%8{^nQL}G_aNn%(oh+_mkA=e1-$+ zbX?$;vIyx*uv`|xEGM~LrZ*syTka6eMg4rFdLOI6MSbV+iP>m%ER*I$uUr(ahV$P) zJxRG=jr;ef2fxk2lW`w5BT2bmRzpr-)CWymNXN9jHT~^(b|Hm3YQA3 zf6lm&rWSD}$u{Uo=);j(e2r!MRefi*5K8CV`@ZxSJ&(I`@JOzKxcPv-32Pk&$z^jG z4X+}Pu7OkwrBWT~cU>Rq8A=b-0sO$=KSP}wN(1W1oa-QI7ShH>vgNwIH)0;XM^0bI zn!b>}4P}HI`hI>3VWuh;EXz=E_p8I!Rv83<6f_1)=fL=SFJK{!k;%jx`dDq=L5>?O zI~*~;lkGQL^ zf0!oqPMMM0URt{AJXD}VY2ZB)dQ%^Pw6Lw2ds82U5;WAEu$6NVV9En4}PRT9aGSII7LZd1=ZaFFI zd#F^;9k*0A=~wZptZd8N7JUa^m3)*Wx9TUU<{Ty0TJ=j*uOG8aY6F3#<$+)ltiQ-eVH4D*E1XR^_o#P<1#Gai(V*|xYDoxY-e9nG3#Ic9slxA`#7l zU;gxe`By${{zn1s)c!L=c~$@P|FZy|Ybw(2)I0dgFVdvLFVf0lOXr>*-PGiHKaVdp zXT133IXT&8%V|H41H386R&UDro;Rn|z|F}q?_h4WV9u(8yGv~@f(t60JHY%1kGNNF z$_^yv3K{+#yjj->cel!X8SZXPu6c4(y(zZIVOrCSaHMxyakI>^Elz(tbF%}?E8FT# zKd6Yw9N<8}PFHgbbMe9)#oc92f9&53mt`PL@ozQD%w-wjA0XrH%{yEln7%QeF}Juq zFx_Z$m?E_gOcikRba;*oRxx)kZ?5owo3qEfrriV6k9Z!?k@@jzDZAP2Y7XoKH@lO0 zveyGs9wMw6^1xICw>%Qzd)>?l&pX3?V%Up0W-qubW1fmX%bcUQTg|s0hu={A+sr;A zS^RIzF^ap(yb|tC)Kn4N1txqTLSi3QnXR!8OiAz`ABzWY17Bt@?lLDS?hbPWb9boC z4a`N8*diG*i66VkwC331H7$HkoXID9kQD%oM$^VolY zxoD!GcbxA>G8cVmBHZ1>Jk8(2-8HP8`377>G?=H&!3T#8FnhiGxJu!&oG+Wp+&$)H zNe@hE_`r?T@Mn9PQ$BUZTMc(L!Zn{gFs*?bxyBhD4wqH&9Jty2h&g7xGdvP5>kCE9 zMU9V1H8~%|q_Pj~FdN~r5+=aSjwEK!ZBD-iZni+olfQBLFz$<~>xE;$1#;IbxJaK-7L19uEEHu z!DSi9@`8U4IPKofcyd?xk?|lO<+;gR+Qa!E4=yXQre}jPkr?4-_a*rrb}o$XI>I!ZZtXg##hH5saSVO`O6%{1@m&Ek za*nl!VLZOsIIFBZU1U4bC);ICdPr!sPWS<1a947~q@JgWQq6RUEjS6|+mp=b1>_Sy zRjT|v(^YQsqfq-o?d8_4hVktSOy3pO?t$^`hnwcBtlbD{*%mY4JNlqTpzcdHpa#ab zhfKvOO4HFg6etyMr-#%ov$6W)^39u`hlD59QV~(e-GT19x;2qYV9GY5vjbz+T~Ck zjQV!_EiMJ}A}0PV8xVu4p!7Ct7eiIh(4>NKQxA0-)%tdyZ}-S%YO?PT=Nt2F#cwqu zQ1Qc_z0I^VTe}Hr2d#DQRA9_BLIpN>c9)s(7&lYCf7ULzOYvQ1THKXvN?UBXVyFgW z-DB-c7~j6ggui3$Wl)RI_;$T)rpArlr^Is8^?e%{g}Ufuwokdu@9lT{qSoI7o3MMf zSvwBZkecn{X459J;}z|+`2}#-S^PsT4_mt#>hvvq1bwUXc_V$BJ#fvt-4DQNs zBPQ=9>&St9f7$O&zGCfhxa;g>6BxC&1GN^yuUdN<)aAC&xASGwfho8v_=xFx+r~v< zd|SFnf5+MZs2i6i**gCXiCw{nNqo;A30Oo!#uN8?Yhn~?F*PJZdN8;^Tx^OLii=Fm zA{$o)b!%nPtX&U1JLKC?*Md>F>xhUM&e-d^yTYvgL-%@HW$AJi$S|2liJWdCLpbR% zZk(g#KiG7AMhu$4=kJA$U-R^_LgvWC5GA`Phf(Ox$Ii+}9eo=^YS9%vG(ejaPU`lC=oKjhm3p1sASyYJYHLa1v% zm1oCT9P)2AG2ia@*l8v_ZZWx&%I`9*P$Sgr*;~wv$C$}}SNU;M?6J!J#IF`)^<(V;qSZAcR0_XdYpNL*u{N;t)K^L?yEivne*WjtbY(H zKJ_20od|U{^q&Y>3(cp#!U*13?4C%4qbXG5<4Tuv`mful|I5&}3a!dKV= z@k*E(G1=9&Kp1ML%=`-e6S%3|D0`ln^cXNhwX#!8?TzF!azjvONApdPv!Jfd)>8xZ z1eMu{t@A&Fgr=ZHq(JYt2w*=*Z&pPSGjO;3LH2Gj-3;GnD;k7al;a*bJ-;h^vnlf! zH&q^ErrzUDlOG|UC!%VRN4CDv_^x0r_S+5B#go6Ur8 z2fiEo6K4Rx|GVQ-7cau%nHW(1Fu`D0Y|}k8xArF=ncu z7Gnq0MP$nNI~|IrVIot}zZJ42kBZbc;jzTouJVsv(uK=}EiDGhXJywm^%>*|7(zBIgmi*h-=9cAI=V??;M@8_Sp}md)bL z{fR#nP$TD-`Hm9bF#%Q4bgw-?_z42L=9^}yRc)SB!I+78+-Wj?s*2N1-BV(!8SaOy zrHp43*Jav7R)5LQWN$SSaQM&r-P&idccr_g`4_h0%0V2R38r7%nPg(mz3=uA*!-db zQ%uE6kcZT)U%&5m;UD~iZQu-i=#P?;Vn6VG6 zJq|Thh11q96=_(N=yICWD8YHz;AgZ#Z%>zd!W|R7*u^DP*WTDnDXp11N(IP(UR0paPW*)v>!6W#m)yX(NrcthRTSOe~+EUStNhVD^!HzuU=K~u5>@<7v@Y4f`? zU1jjj=SXpxX+FwkG(t6`#kZS$I}WSf*zfkjYB&IE;4rL(qfkSif3z)M>9NbiMMic4 zYD$`p!Dd9u+$;rln(P%HxCK;@3)RE%W5q3|>N7Tf0%nund;&HP7>&6$f6s|x)bPR> zK46BS4p4pa2W}$q4KM&(pkBc^d5YsH+hfeQxxS+iPKT$Pc$IJj!1F}vfe+y4SB0Y_Xbac$Omz{QBW|LE3>#2oW3o(yfCUBNABN!yRFbx*aLN-K2dMOR$4m?s;3j4-D&DRZ~cuPyG+SB)~@jQfH6=V z9g)rHzN`r9{I4RRirVGiK=D-~_i`Q|FpcM0zwy{<2B6O4uJdfU^kU_Ani42~yKnbG z)tj@Le0IdV62*0xa*@+`8hU$rA6rg&-qXlWL_k@%QSh6n^uuU*iDcB_j=Rikc}+siVs|;ah}P8dhOODYX7L4*MH#tzHz=8hw&X@Q+u5PdGjgqRy-#1a=Pv-kgMW=*!3BcTO%H3 z#>AZqO~yul$f3$N!x|dU>f0@T{vOZnFjKzYwTVuXT5DUL3)SN;k&0p>7mMN>#6(ka zlk(@8R*@bIiu8QiW85Ux`HS;r`FWnW#pZX5#7{v@b$-2PyQYDJ=5|UBhN%2j8_)w) zLHa+73@ub#hi`ZJ_Ape1sSU(2wBsW6RD2Dpfg*M`|Ma%v+Mqg+%GB=&xDT5OtpN@c zHueCyPzNmV$leWe$M(BJp518*zHZ}6p-#8PZ`d`H`%PO<8PtJ#eY>X7)@PtP5c6za z;mCGzWPZyQsDcWJLNzGyU#&j}dN+$rkUc!{b{m%iqp$6E^Pn1B==&ReJLcPizCG3~`TncHlBiANr4J$9NYsCu&9?F#5J zwH`Z7hey6lirIi67=I{WDju|U3yeRs+&G=~0Ao;dpZky)H$@(KpXjmE4Eg?1-_Gc= z(nrPi=14p3u)yXc!bG}1WkQcY{BO>(-K5YFtk661N zDy|!9M4TU4J0D_m{`-zL>o9{*Ba+kYZzNC^XFh5R)wxY}zZG5grE~iijF86KY+kLWi^Z6@VE(X=HtYNd9I(}oXrh!+izer?%sD&EAmftBZ z)fA1&KhLy}`g{Mh9Gq79uR?~h0(z@fHak_vYt}Ee{EoNap50}J$MAQinVQ#ad@Ixt zXZ-O4w~n}}ah2;b8E@JAa;TBac-z|9E(y&|9#0RDCnPoj5I~kk36QDj5xGMuoCj%eiAX~$e7nlCxk!n; z(kY&=cuvbi*y$#i8YOTELj11f38mPcYsKDZ-Vuz{n*lF6KhIm{y zSHbAPkf9v%m}J6-*m8AH^*GC9$4p#g)z=-W_yr~kr+&*rEc7ZUT5b!Dhz}iXS`V9c zJNZdPb*4R_f$HhF$c|QdxNLSz*h59lCrrD&umko%=O1hXN}(E1EiyIDu#5c0(`7F* zz0eC7C83@bpJ5BMh-^rOpR*P9Kutydnab}ny&gNwva_shL>gAGQua<0_`I#J0m`3P zB!A45zj z(X>198+rzHpgmAikXMRL&%2;HI4zrUsTW&2($PAS1qx2&CZ zi#YHw)DR9`E%NyMWqW{OsGg0B#8+2AhBj}V$aBFpV$c+=hjgg$I@`lasI#D3B)+sp z`CClCxZ?=dgs)ddt{J{T44bT5#8e&>>=5SHW7CixkKCw0^|<0z#hqX(HHGwy+e;3V zWcox#Cim+iQzh~{0dpIqo=K0~sx>L!Wk{6Rk!fmfw=Hggn!C(9@H0dWBKtz!w;`un zn@EqRn*BMx6Px{_S7hjC?h=nMg{{^NfJ6>IBFZv1~tUl zTOo7WEmFboL-hREN6hd}*+-b#Zpc(Edlc?SHd#NGKh>n~mY*LQiHuCmV~{DBfEu}; z$EV%uJv==_0y24rJMC8CD1d563#`OW?^8wG6N0udEe3fh# zUz^9cB~vox%E6*CzlTgk&M0KnR*Resqp#W?6#fC5Ij!-?4)>ZpU@cU`Mm)xO3y#gj z$9Y|T9^u9y9Wt`HnofECou=-O*c{gl{E59j;Sm#sIzYxajGb%-L|R<`hQBCb{Gk*R zcoXW|vbUAL(=<)WKGm2H;EsT4oR*zp;vYip`SL!3j6@;SNYu)v-U)G+)li zBDY{=Gt=&}|KJM(r~<7}E$!N;xSeL;6UZXVocEzOWi=udj(LomagQ-mHXr}4V@>UX z54}Y_1$CU-fEY8a;x3o-FzrLWf=Muap%2}zmw4ZQkTSSvEEPHL4-wfXmWipRV!5rb z8^(8Ko8GXEt2jo?Fnc~@;~H`x2h2WRc8YOM{Lt%A6I27nMOPW8kYJ7yPgMr5P(&7E zlgA{JcpA1AW8``LmKh@-Z!)pLv7JXBWfXTW|Tw+R^Aw8KAxu}fX4Y_$7xd-kz$uxe) z+I6kU=RLrEB3o}8q+Ij;A9}ZH15m$!$bV2g!<0QI9&B2k7jw+;t6qy1ndU#(9_747 z1{Dm5v~+SzfyrjipG4l@k3*)a=?xoS_$D?zEBLcL;Piy`_rE2-?(^+X7sL3DqfPNU zHa`YcU!FT@E9em!lBy}V^As~Jvg-5q+5+Z%dw`)2@N*wfHVs)LF_EoyRAl3+{m{l` zeq_tlLY*}wA45iHY{5rfTw4HkE;R0-67(>-5E7V?B72ExO%s{R;78t2=7+Ggg)SCT zj9H@mplMn95o;i523E+_e|NJHQ`#3tK&_O#hFp}F+W)09ujJVmfZ}w*ffc{Rl7wDn9+a!Sm!@G z*0*e6>uusPQ+u}KT{%T ziU%M=JOWj4ST;i$e-`q)zQ&)!_%<^p@@?3jU&xM{^g-GD&hL5Iagzzvps68S&jj?Q z;>C|y?c4|a>SH&Zj`X}_!en+O^QTF&X>V?WSBdWQzIzpM(lDdXAXsf~u(3 zv*R9R56R|gHUrhrl0T{f_KiQ;A$P{T3QhhS)?f0b$SoOW2KhQF?le>H`8|VL1DR8tX6gwHz$HC3qX5*`&rX(>_#%_ARFgUj5b zZD0vhPnw~Ivf~(RcCySBV!A2$j2JY_j#C`(|2`|5i&V~xw-&~rZpE@rlAkB3lWo0y zP(82BgX|+cr-+M9X1=)8xV>j6V4F$*oE&`PSskZlKD?OW?bd_yLGt^>iInTzmdgT0{AfcfegBp^8;u&}B=luPg z^A*U`Z3*OZIV#eV_6r~*GI)`gVJ6nta)p;DpReJe>gjKXL>9cEaZ|A2AIX59Hq zc`@{U|5M^6I!zp^Au-S9`+n#x5~wLDxl9Fk*o3mD%4PEtZKwklUT(|hL)|;JitLO< z6_CHSQ!Z*szvS0fNxXjlS42V;4_^&wSxJ?h(_yF~8($}~IImS)mnp4=oIZ)`Wyeg7 z$GB;PyUtEE1vQH2mafh=YzC^_$j#zTQ~Oohv8-GC^S^|IdR_$8_I{&#tDQOeAu@JcoSKkl0(;0ypnPJ)VP_`P>@jYutJ#H~0A}<^ozb_^k)2=uk zOg2I48xq<127YMk>w}uQ3AaNTT=yUF4+NDl?UCnqk+8gp&B%>-9I4I6pVFRdjz)s`+nDr?X->#sNeMtJmMFC+s{78H1}A$5yrP4 zZ;E=wr6&9&bp2Tx5rv{Pm36Mg=XuRe?maY(zZ5H2qF-{OsoUV%(HL zEwbEEG`Ae$Dw*M zG%j)(ebd^}KhL-U4v;y4&7D%7$O!eqnP+&t_Z}ljem7M8UC=uXrb(#9dp;5qP3#j@ zz&9TIt(}{?&#R~{DDu0&CHuSz%Ap$4aHyDSQjf54gGbxA{wzp6BO>LhPO$kUxz;W^ zX`ky=R6s&4%{m$KUale!a(>1{Djq*oWUBJ59r&EJ#|y-O$vhkK9x+GM9A7L3P2Cr5 zLu;Vy@RzK;4C>dg?bo^1(R!U6JUDC+1EzMP$S)ylAq{F0I~SQA-<}pZuUl_`5Axzc z%@R5rG6c_u-P6bA8M@>z=skaF(a<$;P<(A+JHi+MOWNv1NVqjRPkMr z$MH5X-SoCwf7K7*gUqo0IVGUpwe zKP{V$DEmFgk4}n3>dD(Hf5?nYTmPiTE&R=CZ2nfM$^VE174?bCas7-KFk|~{#Us%B z1>+~;Hoocn#M>9Llf)#`pDZpgooDU5FF@+eJl|`;cGFHmSEtkqlo2)K9=DqOi)3#%OgA-yo)#@Xf9g$!6wO8_?JwrkcQQ*6z3+ z($a}LAVV5$7WumzcUwF59p&?o>T#Q?Y_<70_sbtOx!;q`z2GL94K7HVD;GO4f1&z9`5!<2|Lq~{Ofd{h0JxX?A}e^O$B=@_>G({Eb4 zdcxWbZ;6Y{_`Bjl)BT>ci{FPFpxPrpL>8&I@dH0@TKU`fHN0$oFYuAbS2Hu>d{ehi z`TYJT_K6Zv{viUJ(eCWW-fFTE;PyjIX_6Q+O$+6Znz|I(3r%IJ^>+jzYiMeT^7%Rc zLHq49Ak_UpJJj<+<bi*5PzH7d_nG?#Gyr#X(1&?**Zp5WyW z)N??%On!dzA#yj|;@SKv-Xp&UfGR%<6+aF2HD30m#B+7*hRW}fO+6DHJ5Bg9)i>X? zKr%Yb9?!ul|Dpoc)_CEg#Y`&aItQ3Q$vdT_D z6I4BIP#tac?a?ZCzxPWAvyKd|W>X?}sm`@FFyOJv6#2HOIj!;SYLTrw4!x0tdf*t7 zpAo284|gu&UqZ0udZ8N72Q^X?t{lv**`SP=8T81bl*bM;>H7m4Z9!27nDlHOMsKj? z0ypwk@_YBY8BhmU=8@kAiL8YN&*sgC$l~j&vki8mB(f+t?K>u+8ZrZSIggm~M!p9o zzvo|VfjHCw`bD0c#&5I!Q7HeIZ&$YLcgKFh-yeXguMKJnhM`6<{2edeHMvT#SI^vQ z11noO7zJzYvjuvgDxQY15btuoYwa>9yIwXU=zP!m(_tg!%QpFO@S*fa%%pE8{=n8- z4dd~D1Wv@ZeKd{B1ceh?=SH)4EF6tiE97n#;rIue#h8 z-@Rm0@Rti0Z`fF~@ylOvob}gVe{=cCuGKCieeT)J{iS@@!J!xyb7 zTD2zp`O6*WKq_+C_TV+U2et=mmmGBAr6ncdudc1Rd0lw@1`d1zO*`%J;8DvrY}|1C z%^TL=K*qWabvNFs?DZR}7>M1MJsv!F$)ao5)zz-OcHK?u|7qRs?+*s=OkB8T-NxE= z8&+4#_Ma>-nfpa&#$k$a3kTD)ZMs#!?pR&B^z&K4vN;+t#u;LzZiUQ zkyq4uBe(o2`0&y->(XD3y*Tb&Jj+gvpllz z3!!sUoyB|t`eWX_$VKOe4nN(Q=Opk61e|%|Jja=b^hsT{6fphDb(5$blOoD8brfr427K(C*y>wgv5I&`<?+obPA|y4oZdr2PW|$bGlB9C3pur@1;tSJVUer89Xf0^N%fa; zbyz#jB9xgKauN>@Il0IzaJ>B9ho}Z+c7>c06h0#4G%<){M}?f8qeD(%R^;h#hyF)W z7PV(b{z5XCt0WDeM%G8<`EQ2~KZrE{D45MCAkCp8`^mUBoRH{F`x%FyljPj<`6Oo{ zT#WQ-k22OsZ9RPT0_WDJlbq+CN^*`mcY(8Y)dJ^&{AB)riDYLf=}mn}&T)sNIQN+( zXA@dqMND3@vxD@$&o6MESh>Kte4kyRub%U1UG861b|t}U(WU7Bwz8)VRQ6YOJw@Z* zI4#*(_n+3a;;&n_^0!IOp*xeD!~b!CvzYY5cO^NG-j#Ik!@oJvZGV-~K>7^936%N= zRuU@T6?6(<6{VZZWm8va6(bGei3to;TfxhKi_@IR8A zuaSNZuKsnB^B{SPHzYYr(d~@V#dP)s>VFD7fo4B@ssBT?@A~7IJA#wYLX?JPKhyMn z_OoP5kkMKiNxv?bdTj0xCmUTUgzQnXG0w`;->a!>&(LFK3l)u1}mfErOVYDFEW3w5JDG>G<~ z5j2X%(G;3NiGN~YqjZ-)GSD)ViNYug<)VC4h)Pg7szBAK4mF@A)Pg!t48>6|>PLfU z7>%GYG>N8>GtNO#Cdx)`9)A>|B2C85EY{`REerl-5bn*1Bph|jM`8KilI2_Mg3?H4Wkh>j;7EIN@M{B{(NB3 z7O*H2{BvL#etZ2+cd|)qht+3vkaB)Z{-2qD1*M}Rf@V*+a=)-HAGM@s&k;kKD~I=K z@nZ~D2kC`=rE$_Je!Aa}AtYhXY?{2%=Y!rQ$LVo8lo8}fK{jJ&F z&vSA}&wi!{gWMh2Pk|p(h*?T{x$hrfcn|Z_mH0FLhW0%dbPo5^)%cI_zBnYXmW(6) z0?nkue!7mJ*-sah9_1U2`1z-2y-zD?Z<+!L&LEAGJBm;2^7DG27GS?`5Bm1-LK6Cn zycK!7HMBhVL`sTh>yPN0c8h-fVl6}a>1M^xe#S|2EpR5`wEV22(gDtQ>YVcHP4u_) za`G!tHL5|is1DVm2GodJP&I3!4L-po{aN&qNzxK!z9%^iQQ%$9YgCGAP&4X6!)OYn z{)G(;<)eBOL;YwRh2LW%L$#;{^`g`%>O*Cy7PX;1G>&Ev|F{wXd)cH=6>2~&s2dHU z8I<)tn+vKz?I?~0QR)X=Cr|~dMIERYjiJCad8iT@6i0iI^C6oSszlAG*X56Kl=>0Z z15|<{H{ZC++2h&WBA& z&fe1(I6KZ*;2eiuIdY+M5BWEA1)NLW7r8&8mM{0~n^c5a1_(ZH{Bo44w|Wan^n z`yv{JjzjOJF}$}hZRmCM3ffHk6O7PNjLNMvb~Q@-EYBN^&?^NCoXvM}{y#>mUrtY9 zXamklw3VTJIKX{BL0?0Azs!Tj^^64iI=UV`#t0m`0Uy0ubz!ozY5fA{4dPbAJF6Es z_Yt$6#$UilyiR`74UF7|13t|Vvk9nAl69OR8l0?rNR2AoZI&};N) zd%#($N^T;Mc}+Mn*}0wy56ww-o?$LuKYW3+o&#Qt?@TIs{YJZHZeRhva0LhA0Bh;g zOO##u0~R(5@)Zue551h6>>Ntm-a9E*!5=qM_>D)He{=zQkZD*&CHiPzuX{3NuK^gk z5>_os;52lc#l8~%;y6o4S03wlS5|H4AMM}2k^c(td!a+F&brFs`Py-A;f05;Q_029(c13(z#N`BbzFjgwCQ0b5`P zurPM#2;lJ{$(iV^Z%K0wzd6mh^{Z*lq19>5ao40dH`Js#o32A&N^|b}a+-6> z+B7F^9r2fvcRA^e_%EXD>NMx}HRS(en)4L?^(AS}{WqjJSCa1@`b7+!r(i6+n1h_3 z=Dc+YBKX!T(wu!4q&a8anC7glO>=Ty3OS?0A!m}FkD*aCf-><>;t#-dG)+1ehLMBn zvCDrIa{6E%z0bmzjh4L>a-BU?FoXtBAJV7lYg}maxwIY3T%tkrx1XxR5}g0K_-^69 zUdex<4)?#M7ythaIQ{>-_q+G~Fm!Ojy+f}qOeyNJx3Yy@ks~(q0%7x}*@q+EF8X(y znm%4ea6@cAe=jD182g07**d45!oR8KKZ%L_Xme=sWpfJ`|4rf92fx1;vw#0lpWa_z z$t7|2Q`H+;{y^yHdGM?ULd#Eh>#JO&FHLr;dJn8mm7VS6+_KfZk$+WL*h$%x*|ONb ze1JiFnQQy(r*uwx6P%Twwq?bf0V$soqk)|*dvW`LdMf`;%$@fih^e+QkuPrvEe`&5 zM&zysc}293caXE6+P5QbZ^5_pjsq3czis0-^Y(7`WBjYc&?O-I~?$FZUr4M{M z-_D4AZFf?_9N*Yq9r3_oevSn@`-yd-*@^P-<0orYWsn>8Q*vR z<^#UKq<2aNx6Ub>;rmXU9o*Wk*>4#X7yotUrn9Ehoy^cIVI z=I#T&x;f=^VJOvs{L4%KD0j7wa-X+6#d+{t9#Qx%<&E?Bj-{XPYdU#Q<9)~`(ueY0 z%zAhndJEsn|Hc!>u{_lApNglUzp2-C2B|pu-(Rt_hk9fG$9j2w`hRS(Q~TdE68*eM z;#I^vXHW_6(MIFV55ci@-P{8;`Xf-2q;C}rUv3=YHoVHC32H_9)IQ4FH@+CtCztf> z$Lv0kuAk!{rwg;6$vNq=IWg07{EmMdl?lAcqsr_jeNIO0oP#Z!;}6eC=gdjx%}H0z zIdCEVRje$1O6SCsf0{m>XGM&Qd5fY?_MF1ip9VQjc#gjo|LVS^-9On8dO0B>J#yc! z(2)!EWGUSec|xWhET!tm>oWCNDpf|(;-Mo`^wcUj^CPFmLq{x}yZJ?r!#Q@67W&kI)Dq4^vhnmWL@sji$DuMifQSkM4*Xjd1BwXoTMs zHK9A@VG50=R22QFsnNzT@-RjH-`{&b=ic*oUa#Z*eSf|W=bZ2Po`-vO?v?xceU+!~ zT@YtW{di&XUiTi(s;=}Ls+eMwGQgC%)zy@D{PTj_l$zE?sW8d6!9wy1KhX2S)m=MI zYZ0x?xu~~NdbU$a&qGd48f9%QyN*)X?g-;P*N&!!DxX+Y6%MsO0M|A* zRGj$3P+fHDe|`Dsa4-4)g!uhsyh~?8y)OC7bbc#CH5dO7&hBJaUB$ghby90j8)^+p z)C>HQjKsU_s)ZEz0gi8HSBvNkoqrY|?7nU^HHN$E+nU-=+~vO8)}&+0j)v+iRnjOr zkR~I=U%;EywyXBy+4ykx99z>G#+`OGSE8GVwsvo`-Raue$xuBoy|_|%So)(m{x^Q{ zF2mQOIzNVfyMiZ4D{b%{Y=5+PGJc%?iW7eXKS=)FP}d&=Bf1$XPxAj`Q$y4y0<9$Q z1_h4cddKJrt8|5g;Kpvp6LE*+AH{EWH`EkHk#7U=`tEHZOu<(t?EEd0{_v%QJyti7}D+ZB^;U?^vCfUc$RdZ3%}CY9@rgk z;zq7bJt@mss>@dz>QXKLa@OG2S;lsAJT~>X z^z>=GPB*)%Eq)1K(Z#NsNO>D8HjoAM7mvm_O)}I_DIbT2zGSEclHV3zg74w1p*J`& z)WztZ9vs0#C@>Q5Bo&^-7vknnc@f`_-!1vG@z7U;{x&{(rlD>?y?{K}Y;K6USIU2e zcW3whBSYhB7lDCK+0~XPe}&`tu`zU!6u5++EU>FeY2a_%$u6NId<$sEmK>aKs0YOp z@y2g4;>9!ZCAhf@UdK1#c4^d}AU=AL!)KIJayU3+JAh2;6gI^YS03Y~{p}vuQ_y>M{W$>i? zFJ7NP8z}(be#|nchvVgVT`B(pZUlPJeW_Yq*FuJ%nVnDedfXgh`|xJ# zjKCf|if7=jOLLd;a(s_?%?Qe`4|Z@1y!D5M%8d2*Pgm^;c6GU?-|vf1?l;1l)jYB% zcpe-^nJMqMKMQZ-s_|8D(c=gY#!DCjx~nJarqk_ zfvFV8_}x(Bq(BZn?-zPR{C&K;)20^53Ve!RscuutCI2gY#&VlVk^GvW_LYAVPqnn?T1j9z`z%fhe1gZZ0FE|ag#&n=WsQHsr_cZ$=F9&V zpMW!De1037HjDPS-|=~OJd1p@y%cf`?3PSw*sXkwy*&$d>*B);l0WCuMqto%l*|+OM!Si zodV6Jfh2q=&W8FLd<^f)3Yoj?IsE3=w!j(mb^KhhEpSF$jnDps&6O42gx7G{{AXYn zduAVj8>|2aItz$Wzv79n*;Ef)k9vIr*nNggaiiq(P>zQ6vp6i}Fl~TO=GLaO(bi@q*=y54}2EB zng;Z!AAz5WvIQ=?&*BF;49$zqRJr&6RN{?4w5eXQg?2W5VGWzQRL{SKPJCVh`WkF^}8NAX#VA^)h4 zQWx>%7I(1ZMwDj{_?FieAH*Qmw+Ft!eFV}h$LSC}+j7`V#B=caQhpwuhsTNM;YB#h z^|kjIe$58$$U;b2lL5@DG{JscJ znHTN5nbjNgAzom~-&338uLT9n3MVKKj_c!ESGbCoSSnQKsGM7r3v)9HooeJO-0K-`T$>eoKSrE!nSl%VvE3@Nck7T_rHEc}U=<(9Y-@_)v)Nv%X%T z>bTJ%L`{+vipBeM2~i20Ky-dbe0p+-S|dH!AMaNyB+w&I;WwKEKk&SUx8@Ue3*QR5 zs;LD8CbIy280iLA;N7c*sIk)EZhXgDyULQ|_7Hxve~8i#A9VS1`0!Wks!DoDpCSz& zx|lua#2a&$+*{hOhwmW2jdp$gZ$_XFx5cfbz@56nQM*c$eV&M~<=Wa_^84UdXz&s7 z!T3Vz_ZJ_DZ+(g`7oUhbM}-7Ffw=IVU(-G-?7RNYAu#fYUG0=DT8^*y&aMh&1@drX zT!;#j9x1@<^YP#8vE6vYc%Em-Ao~HY9alYYt@s)5J~2db^7Hjr8GeKf8mF)Sx(lla z?0+#t9gqb?HQ+<#_`>-iYLJxghM&aa#QWgJ zTOq!~T-P6o@0qVJUUK~(PhieVcBLPL=mM|egJ;-PJ|8%=zo{GGX+&*q*R{WkPkqs@ z`pN<}d=cjg+C;kY&)oTx2O~>Mm3+#a#l$rQEp2xXL zWPu9^jHf>rO9LzMgi7u_C4U26&ZyNF7rnxt;Ta6VyTyy}#slo?Bd#Gj|9ku(&v(9% z{8D`36Lz&h{3^ab!|n>~Gdm~!ss9T;imZ#T!07;AgRSvZI7ge$d*ItF`GfEsxVeH) z;pKP-DgQEF|G1sH{`#}=cE_s+7qFN>NB91EOEyr7Zcsxu)fOLyo12x`m@zrtQs5y9OvD$<0@Co%lAw>pm*Fhe z*Dq7>t$1_sH}GS)`Gm-g*FPCtfn2;XZr0z}m@(PiQs8q6B;tkAU=e;3FBbn1-~XFk z^%5_|oxj^vviP6)Fq~_-Zv_pWe2l?4lzbkIPsYt2Y3w2})e^V^pKkGc@fj8$f)6aU z2c9xMg%88c1-yi3So}47yu}ybQ}I$+A=erLBTohQ$*1^ai|@nd;Vq=XPxvOBYp-vM z%JBWTdBVPqC-SH79+0*B*kadQjD z;+ybrSwI%P4Zm01jbFF;hj{mM!4>!nABg)m;L&QTh`?w9=AifqpJAy`hA+Xn@A7T& zHGC~TR=ipq_ebZ0m$bTgcX#)Oce(~%2woWjI5Y7jmi#IBMm$y8%f>_h zva2NVm3SX~i@3KLJ#d|Xxw{Wi!1&v)xTyI0trTzUE^id)stTUKYtn1$?+6Wy@&@=k zo>wPGrS|w6S8xbyzdz(J6SA0*#A>|e%R(<#tdD&!ET zb7!!DWq1Z|R>;HG(bdEY+41@Vq3T{)hk=~rYCIgQ z@;JV2NU&3$$Gf|)Q@4-1eq2*yw7Yv;Q`fu!p@Bd3?WRQilu(stla;`CKNuRgp#6al zdnhz;?x@oFxOrz0)spKCZf^B$_{c$_fe!>7@l}t62F|X%TdJqj_+i2Q@(2aKqrzP2 zg{O4`gF^$Skr(h8c)H}f@RRrm@i*~AHhGlzJNT+0?z@{cakZvrK9HW;LHNkfV6)%h z*KzYE_B6hc)#@S5T*u4t0`VvY?oGC1P>8>uZpR0X2n{@+xF2seGE`-T`tu)Z#rU4X zACO`s@E8S_Jrk-nNJl@5_ZiCq#b3o|j0+9i1<%Fj;dWVpmH0x7e}b1hP~DfWKkV+r zmymCco};Z8-+Kv|*Rit{IA-yG@pBfhaXaU!@xk&f@j7_AtUwQZ8E&r7!}yhnp@C1& zPvN6q2sN*hYEml#hlMJB^JL6UyFy!3Jk(G z;^xVC9DWQpxA0Z`q^161{30GF_1EDw<_Ay41ug>J37A_{jQ7LMlj*PcckbZH^D4eR zH#k*MA=nt?aA z_#!+JH@A2L-p7)^9q(uH@9}{+@a^J1NKD1$G)Dj5!5|@Ec5zL72i`&|#Nj6`-T@E& zZ!o_%-rC}+_&|$4hflP)3txi!&o?~im`C6{0vwgTHC%^ZxA<bJw}OX|r;&%t?Qgx_XP>a1Xn^sVk}-Z`)jV1|F@%;xmdu19xU^@jl-KFBRSK z@*hG2H|8n0Iq9W5iMKl%?17i?F1UGvxe(8=g_+L}UFt&u-R)t4TZ}?{RajVHAAgUp z$IU@@8jq+J7B~g}jqi^L3oM{+doE24!qib#Mt_Qq$0zeAc(Z;td=;*Hqo!h?rVuzt zz#K%+;H_JQ1#ShW;TaZx3*U&FW8lB|5jlSZwi}$|8AHT&%<6FA~xA+x&o5kngJMcJ`<$HLwj6nBpVS&&2 zUVIFmO#$77NAQbynQTERe(dfr6;Ge){A>95alun%SO+dj8UA;(bbejjxGyYl-+LE6 z5Z_}yyy{J0%5L*ASyMfRPqX+7c#Wj6z+Kr)d`xoi-0i`q_cixvHMJRU+%GKf{O}+? z6_1e(I)%^iIp-9;hBpZ;BVdk!S{>;kONHC<>HUKZ+=G|n=8gFfyzu~km+JPO!OcnU z(uw%8fnkA%U2o#Yo@Gq1eBTPJCU9|lSm2|?7QFRy!BM>zZ)~|*9miW*{7*c~@=?X! ziBY~REO08VhbO)h7Pxb2hfl>_<|yt-z?^E5=%)*83hvX9_(F@nh_A=Z9?QlL;^vL> z3cTD>J|8!D0&eE-!yA7R<_cV2e%xGCHa8tb!uhXhp;3l~MpM&R0gFoP{ zZ?6_Ocb~=k;bSHLUtK=FTHwSJ%V3#@n}e`DzQRSoT!BOa$8fU;9>FhKd@R1VW3|Ak z_ciT-=6zqXD_$K^G$={5h>|9MHiSNf<+q%$o5;&m?;I+js;8!eebfJs8 z23N2a-V8T4pcOt6H?Mx(@X`1vX>S0&A73o~co**J%&8`c(G)Nz?PG883HbCO)dDxG zbMc6WgDboW-!!zEd2vx&@X%qw71)c9!OcN?qzlWx$-^4+?*tXPfyb(;EEcW@RajRB zNm{kQ9ZwTH5s#DnPWYVk;0ir}_uC1>C;c^ALI+Y61P!8|;)Yk1)E@OFGoQh4AvKZtL&`2X>_UDgsT+! zz~c(-#;ANZJTT~D@wFCjgYUq5%L?3s8_R(yPRrScgaoPf3i<>u@9r2BL7M1jvNW$C21j|2)o0A^2 zkKf{>Z}G8K*W-VJHGsczi)Y>9vv2V?Z}CO9__AC4J&SYwXKO71?H}CYn{M#}ydyne z9>>M_k(N=4*JFJ>bOPUN>7hUI@% zE)_n+ad#R$vuFdXdS7RO8#(sZ%CACV;)v`7h6=|QR7tH;KirTa$=c- zAAY5}N@ADj2M^2fBX>rs9Le8;Z@Mc|xr!w4HGw7U0`ssti6_zn<}SF5*WhJ9-q`W2 zaMV5QqJ+r6<@Yu`^s!+1Zus8J$iQ>re)#UkBUP1*kqmrT&nQ=5A3aZChGmevj*ssj zsm@Ceyo-+<5M01!d?9Y0T8r=k%6bb!|^fWc|}v|zl_&^9+&d-@bYhi`+OBX{FBJQwV?pt z@1g=HCSR8xB5=^+r}6J_^Xb@ieEP)5z-@G7A`Rf?EnE})qQ$%7^c+D;upWGlSa7#86 zzZe#!zLyH4@QyT?E-Uns&c`dIOXuS!)yILs!7fyVizD+#}-VdEst+^u|a|G5#(chEK%l7+)7p!#5Rh-jE(yj4z=_ zNBQ$z>Qe%<4@Cyv?=8Z6eis?|F!~#AFh~a}e}k9tQ|+VFQQ6|io~&?ERN$}2arlbM z!9kmVPdpVo5j})2t29^e{%UF_fe6;f+@g*6vA-h&Z`<#|=iCUMxlZ8bqzBn=?j;F# zxN4BPc1z9;eEq+Xfxk*c^-?N-ZFS$v;QB4q=J?*oDAk_vuZLqN{7N)CTW-#J;f;BH z*}R_~jCZkk2Hw)|{_E&O0>cQ{SQ*`*3vXwsFdt9E&Estq-V-->?lyd|CI2hjob;xC zgLh=OryBnDf5qqAAEhpt*U>WsruSy}+WZCn#MdSVD@5GSb?|{GHCGyFfluLSvw3`V z#OL&jQdulaZ$L60(LYMXi4VnF;|s(`;@j|S7k#8FJWHVG;9vuj@ZI=OsW2Vi8sZ3? zlHS1U3}FRjg%{z&zjOp%cVCT~*M_A^zpjJq;cv(N1Q1-?$8{tFH@LJGLGzZj*`#aH6Se;sO) ztl-D^)XBm8&+y3~I8-kw|22N>%d7fbYIQ+=6VE)Vaj(4NXyH%H(N#Od5sK5>UJiG>9O^KETEXAAU2K{|} z)vpevzxk-ooSX5EtAqJF@z%dP)HKQe2Jg8hn12jkd)lnebF^{-gVzNMT*00D9f6lX z!}@X}$qVMk;8PDc0$(I-ickC?nBN}1SsXl1^ulLs2<8vQk9{rq`Z@Y&0t-J17I*<~ z_KhR(M&T@cReqG>uN%HCUW|XY)v0o2m#x89d=sTg#5dyoxV399z5`#+mvu}(h>!Wl z@4n~gCkRAX3Y^mgK8;eJRr4?KZ+saIHjxIS`f;Lp$Pu`j)y22bpqbwazfOCmcg2TW zJQ;7fldCD$AKw-YB{2P4u2!;uC-5srgQI?|Zs5D9z|G!dyz%24C2|zJj`ukf{K&Hq zpK95lRrsl&gY9j=N2WPcp~3O52a#6?PDZJvGU#^WM~(+86yq(+gZcl%_p-t~An?^c zt^Jo^{w4h24^e?Hhuy?Oe+sr2&TVRay^C1BuYp(sSAGvR&=MbWB-lU)yu0i(y~0WO zO-qjrz?aZN=EvMe@Oh_$?TyBdS?W*5uUv5`K1cdjz(ru&C5QRlNtJ`2yv-3fl`g@{ z>Ef$2@+W-7O@~X3mB1+ijcraf zN*cJNEBwcy4#~wr4d6sImE%@+krO{TGnn5HpO@uOLnS{R?>;w}-xc5VMzH?<_>Qx# z;AfzI1ooee3VcI+C~i*rCUV3ro`FxShzfj6eNN}^H2)Y>LruXCk{?T0@3PtWyvtE4 zM>cRFp5dzRRG&y-HG%q9+2^taAK_c8qSRsOq0jI+H=+U`-1p(j*r(=U_9Ncia+saQ zk6HXGKGkv*rTi{@YxUsr4y17WMZ`D)r_Li3D8~;;g%bSa1&8`k7EpZOE9RoQJkZ<-#U3_+JM_?DWi-m<_E*vI|x zbM=DxkK#wRIaGlxa16exz9Vp-KM5~y7N7<3WeM!vl0=2HI>SY~&s z12W2MKFAiu2MVa>_~>vxYRMLN!{@XK=J&$4ZEytM(jJ6QZ0iVoNpv`Vv7ICEK<_Dh z{YHm+-M4~V|6d?5{7#3eEBkmR-ti+x;LBegd}2pO;9R~Aci!btOJ#+&;_E+l1fH+$ z$Jcfa=KqAx%Xb7me4fD*yE@bjU0+}SuMs%4$)Q?F4@5k~m`LE_APZ=YAB$j+$qM$s z$8_hglrv)={9=?d@WCYmKb6Q0hLnF6cW!kA&aAKC5lQ}C?7RNYCD6K-GjR2L7oXb5 z8F(7B0Y7%XL&eEH{S+U_w}#Baa5sM4lK(xvY8OY1lrP2W_YT&t#HSWI^oxf6>;Fvx z-6>#hp@WAe^_w|W6X}6Cd~mWutrWit@7~<0!o>&R7as_YiQ#z9+nnmCYM1 z%udJaw{)sln_U0h1ojSKpU4{L;@w9%1B1wm?@n>3%aXqr-#X9{_@>ei_^?5az^`Wf zhR++yQ6uFm@l_W8SJ%fcxnvEa2Q!Es;kcGD&;ZXE5p19(J{fN=4R*wr;hm*^BHrx0 zzN7IUmILsEkMY@0%0G%nyyZ~iWK4|4Cokms|AJJQM4)^TcfC>|3m>+`q0Ibw_||v$ zY$y#b$7{Un2weR(;^Xl+X>TV!Z#m})Y400+;Yx>UD_(-{$mROKMk-t)P-7Ve@U*Fjoc#wY&KCp{3@KLP~ zz7>C3$`8XEcXO)#;+goE1ZUuTJ+I<7yE_A)wmrCO$vw`%KK_6}L}IXu3-LMk2JZ(B z;pgrPF5q{(drznOMHYA!uYbQY@KDOZb$ntUXW*f5V|*FjN_x2CP>%oI1U{8OUkXf3 zb_SlQK8bgEAecWDKZobbK6c|P25{n%6?jjVALvw%%P##0U-FPMa4O${I|uVuX(|8h zP>%oBL!62qmhtW5lN6{w)EW2=p z@%r0YW72woAK}g)gXKTR_fp@yAt}N$$d8foKjHhyUn3sxzGjAHkc8m*UrPa||>{<<$I{Gw?^^A$T9$ciXP7 z|8oh9CScw&?Zx-v<^ql3oXhcaSwJG*?sKP#6CaOn-N_gbpN$VBzmfP(e2m4b@Y(oc z@_pC;+c~LM>@h#N)KvH28Fab%xnLr`0-qucet_565!}L)c%sD{KE?*&<}P~---xG4 zeGeYN3b$eTzAimPpbLSvQXrC&85U2*=i%{^pM~eL!g?RqpoQ1)p1YiCknF-`_`*VG z;Ey-!@qFIP%Oqcy-+-_2y{E_VuLD~NKmRh>}5qtq|c5x=2ZShy|EKB)W zc;Pi?;E%ow@Zu`QfGltYeu@>y6VJov6?6TcCV|ZaA`UtOpM-YejlT(=NN(Wm@Lp2> zt|vHg;bG!q@u_%w@m2VG-0Xp4_(q&tKVJ_-r!&S}{0yOg7euNi1ad9j7GGoWu6Uls zd*T}`o{Z;P{6XBD^gbV&Zkk>JUU|k{6FF73K=eM!C9njK6F-P=#my}Y$>7X~pO^eD z_{N`t7pqKs`cY@#*J|FyHysO}8Nb4h;I*ax^$d>xasu4#`BtFalRTBek1 zpR#@V@8Dx_z4m&Azs0BHO~k7`#fb`c*!=n3aC6di67luNgD0Ytr(9;XuD~7dEfq%M z^-nm}lXA72e@p(FTYSeYeiWZx!7ZDtP{gSJzq}Y1fm7#$=ju4zxWK8=@NYpX-j45L zJE*6(c=Rm|jKlSJwaroe626^Lug{G7XB21Y@)w=zxYVDATi?rbc?eiv+*^fr=0!d| z=>>j__rT4+3l`ksd+{XlH^>%#bBq5Euecl>W99$f`4I>LF;{~7+&23Edo-Rvev+(E zqgy;4xBe-%D{lQFP%pfK`sVL+4Z<(ui+w%J^?&&P3-GQZUPS@(+mO%S;?wYKPBi8q zoqLOW@CD?@$qK)Ji+_yglb@sW_4R*;HGm($t!J_yaqB)U#asO43_K0Lj;C9^`qQ*5 zlOEJ{@RT~yfy1r^Zk`!^*Z=ke`d)ViUODc8->4O=FaWoH*J2o+9~~X|F!>~&Qad_u zZl8c#+nbJCUwNL3FK30gmiVv#ZUTzmvU1q{gKmX(nVQ3`c(LWjL5uO6@MvENJxKq+ zr&(M*!vZYc0^eZq`|!>Yx<1FhZeRp~ObVE1rg6AA=`MT$PyZ+QZIhXJvBeiz%EwWD z-7W6LGb5wb;t>Dxip_j|{?QeFBT&i~rbvNH_+rZ%M`rSCH5QM<*I2wKUTN{+cwgTZ z`WHA6?+_OJx!Ei{0e7uo;kpNw6F5$wk@%;06+TY<06wak{@o0J`Eq;~&K~pC{|nEy zxhiBsE4aO6AE*>uVFX4F>pNCtInz!*r zt{QZqoI2mr0gG?I<2VeLN`qT&@$Gm#`3od}&n;ezcOXAo@{io&Cvcawz$pR+ROlcT zuHuJr^QZ`W_Wyfbyv&l{5|80LV3zNUx3KvAc!I@;Jj?NCJ#joifm{kqk`;L77JnYk zBi|g9FW=%WJfHkgQa}3^UvP^reU{^|HfJJpkgcac3(Ki;+bzByPq5@4#nUbR2R_N- zSMh9%hqC73+;;0JMqT{ZQRkLGEPi><<_3@d*miT(+`Rij4~25_cdt5F%e92m8w?da z)f67!B9>_9riatUVCLP-|G~|vC;qkga?%s1w*}ryTb-G2lBdV3IlWFy|L&}wI>FJB zM*Vk6Z;+Ztr6*`aPfg%MaGm&nSs^{`V4lgs(rDmS@-`FaGmv^yR%R;Hw+woUCSQL} zsY6UZjMEc84WWJ{{w4K(Bi+LHNy(q*`*(*dNXxSn43#y#K$;)XQhUYw!!lxe+DM)C zG^VF%#NQ(Rpm-xZk$UZ67BPJTwm??qLtRF1zkX$Q25c$~&ZF=cWfCcT03SMYCiqc}gv>w7CJ4S$t9esjV%^`M>ocx!wYbhYB2#Yj`A zr{h%A(^|Zxq_yuLJ%q}yOGEtHwC`&gzrwF6dy;q^$_vYkdk$=6dDWxgi9fY@8)4TKlr8`AJ9{C3Kv;pdol;O|J@UfKwu>;!2mNB@lU zmlVii*3*w_p@SYSLEd?W_0sZ&#cgd^p7w1bXk^mn{8~Sab4AKeAk5T>@Wj>K| z9%3oX&&q~2)sF}|5YT_))Kh<4zj9U&4uB2F)4ye1fqx4p!Y;6q27ANl%;uz%O)ReC z_ux6yIZRvn_Yl8eIUR{VPfSm)MkGqftmSt#f(rLjNWX&QBz-se`n7|1;NMbdIC*+% zPP`p4FX>IPg;z+gWNt>?Ldxx=j5!^^)1}-&>V2yBzn&hXkdr_tybtmtFlw+Y?o z(>d}65ZBWSG;++JR6i4YPs->}Kk_n&^(t{*A5NPfm z|9wN(YV0;m_gEAjW zJNslA!=;>)_!BmUBtLEBoAh7J`%!5%{vW6xH0UW34k7O*{E14>kv9<*LjKU^o4QHk z&qy5|%p(0e+(NlZUn!oz(DsA)K|F+Xp8iT}brSoT`!MS%odWA=a6J4Cf1I>_LjE|e zr)S;UerV{*#db1(Ahile^V4+dPGbW`;@ev z-lqH~#QGEahxrA{=_!hIN8&Gv^TWZuX&rvMd-vg5u58KC;bKabQ(`kQ2lGj4|H9gg zAg*7E)l&i-E9vRv&6N6lSoVEBzKi-BiLGazPkNS=)&F6}ZN&87zV!5hE+4{g<3E9X zi_B(jOd&mugsC+C9O-RTTFmTb*3&z}v*aJ6&Qg52#Jajy9jP_uG3-Za>2uPBl+x2C z$gkM=rq4-##;Tm5m0A9fdP4HFjwe3F;x*-tgouu0m zZzpTS+vR23uM`Nxiz_Ye_%O(&kdOuY1Lh^?cte)3qKW@+hTx zQo9bNo+90k_@|^VGrxjwpynvjdb(R$)M@>=(Hy$c=b^RpDtY?MS5Wk&$+YZt~?=SXj) z&PIu~Bvy}k2R;G*OWv21J%-=>NkS3q|uj2 z_ho*Ycrly;`%~^|8fk#nf?Z)5adYZL>?E-^%r}@DkkOfijV0cgIh;9%cui(K?Sgak z2+5`qFPV?P)$k0Q3iY%bR%6yLE8pP{`Ti|oMc0!W36HRld!^BMsrO&nXiQB1Wqd7Z z{RiqFC_hOy@HS#INH21a{`s~pGpKb2+d(u&S{RFu#9xu6w!>5K&AJTp{q7lM_1uSk zPT$=5fA)yYJxWuI&{rw*sJn(y%bj~Fx5jjADziB~=^lLg_BtOBc~3%Tg&z03(+!Pj z?)9hdalUJ*@r(Q7=~@vlNo1S5#>ralxIe-poNU=qqI-43_}Ja&j{)uWNU2vW^`BAMKj!2f2xR>;7O4{A${%F|oD=b`cZYMpB9N$2ZUal{kOZ+3| zFWueCZVRnObc8#jtX{+t>f|vSx{vBCBh{U}^>C`Rn(p3M*0k~0MD$co&yvo88O%?+ z%ggR`otNlYxJAtp%vTu;q(@W%U zC7lTQZ)JQxAaO>@6cbP2C*XbGo6VPow!&i+IO(simP&lDdq;V_cA;Xc;HQ$-1y9K0 z9)>Z*zaVy8?>N^stS-?C=IhLQY7X7ZzsZVJ!P_a=#_%Bp?kGxFW zI?W@m8pn&Ca!KF8{0Z|@HlADkO;A5i9L4;%yV=>>Tx+HJDw_I$^y9FY+?`a}jK6Ma zz7BbR5WkODq%5Km=Q*R=%B-g^$-Bp&^u3OkMxC?F-!Ml}=XJ{Wk~ZtxILUoZ;VOb* z(%?YSFEH<8)>AJkCc-6BNk5%5r!vaaqTYD;q}y51uw^VZfs#Yue~2ES=v2Ix)Q%(e zkb7W7J=epOc#5|5^gX#{lHNl=+_?4B;e-WI;E{tiwEnf;KpZ#+Li4@nHhj(RhB;ef()D@UNflYv*bV|ABTElJ_z5{bmDjkko&U zx?kb{z(1MwG=w(qApKwFAEewKSRH>EzQXKvXPj^9`ijVEmY}CQh^~-y3*uqSddimA zIN=Fm=OkT3nf}cGVTqTBmD5IVU5Tq!6!EUOIn5{iBW3=g>}i;%ul8TaLY}Y`yq6je z;n5O10%Ixn27Hi;4Qad^WrpEHY3xyApOH3*zlig{2&l=-dg>Y`%}+1xo=*G8s3eT3|Rti3aOT~xR$vAu{Wu8Sn{Nf+J&!SevNq%L8p4|tUIfSc3+QF|ru|gv zLF#kzounJWyD0OIp0zXQ6PrxkWM*@^LjDcrfz0Og3gw<*WnR>K_)jV>qe4%~{T6?b z`6*%#P)JWvxSsy9G^~B4#K%bE|4RN#xLab&Df60cM?8x%W0`9ae_g);ZD($QTw!iT zp=td0HTo7KOQ`>Q8|~S`9HIXIv~+y2aH&xL_cuD8D_kSg|C^PLZxH4~mkw-~fc{@T zweJxY35$h?golMC!ct+GutHcVyezB|-VmyHc>_u>(EhG}!Qn!OFh*Eg7%OZfj1#sH z#tYjDI|w@q6NEj4N$4iZiiW(j8rvxPar1wz+SNh}wx5#|Xu2=j$ogayLw!b0I5 zVUe&{cu06yc+^jqIxc|{VX3f8SSh?LtP{6 z#tYjDI|w@qdkB++y@h>+DZ)X*p~6&QnlN3H<*QK=$P|tfP7qEKP7zKMW(l)}Il=|P z#loe+<-$Y4!_as9AD2LhuvAzktPoZTFAJ-LH-u`X>@Tw))vODl;gjV1mc7( zgz>_*!VbdD!USOtVQ*oIaFB4QFjbf)OkXL-|0oGe5>63L6J`l#3A2Sc!Ue*`!llCH z!d&4RVV-bUOE^oIEzA)v5H1!j6)qR%3fBnpgd2qU z!Y#RS{1-@IyRcBWM_42*79J8F79JHI7nTT1g=NADVWseLuFJo#t0Ztk$WIIUZ%l;Y zLWeL$SX&q?Y$S{mwh+b(+X_1fJG&&2AnYMb680AM6{ZLW35N<(g=xZc;V5CIaGY?0 z&^1XCQ-srmS;ASuY+;UYfpD>Ksc^Y4SGY!)C)^;+_tT}eNT5KtU05jGBPvxGUqrNTABeBpLsk?^pvL|7rLg1+P5{=R=pV}y-_@xso+Bw>m$ zRX9pGK{!pAEnFbm~yf4T99tj*09v7AgFALQg|B5<2cnn%=@K!UExTVWDu3 zu*grBDwe<@;bGxX;c;P!uvAzktPoZTFAJ-LH-u`Pe+BKra34AT91@5T))vMJ8wult zErjvHw!#j=&cXy?4`Gt9x3I6KKK@fAFi1F5m?}&YrVB?2Glk=X6NHn5Q-srmS;ASu zZ0I}wb0n}pxLCMUxLlYkTqDdAZV=`Rw+IV_+l7U~J;I`Oa{L!d;E?dJ@Tl;(utZoY zEE84;D}|SZRl*xW^B3RMOyM};1mPs%6yY>smT;EPl`V-J;R4}e;Zosp;TquvVZLyS zaJ#TjxJOtdEEXQ})1?ke;HdDputZoYEE84;D}|SZRl*xWl_&dJ7%p@OV|?WJt1W>z zVGCiru&uCzu(L2hm?9h`94br|rU}!9qlB57`uHCwfeFG%!YRUO!Ytt|VYVThEE(@!KH-zc~+4sV5p+guWtSyWcHWJ1OTL|NY zZGGhU>mY&7!USOtVUn=7u&*#hI7m2Dm?}&YrVB?2Gldg04gPw5>4k_563cgwzf{k4 z=tKV|9~K@J9v7AfONC{^3Sp)2vam{cL#Q@LmkPs$4nJKgMgp~kvBE~eIAIH6ys)jX zgRrwOLD)l>BqI7*l)94DOM?sBtyy{W-L^u&-xtsL|9@JIsjnr0IW_^N*`caw~;5gpO_g+O>so!Vba&VQ*oY zFjJT%%n_~;<_nAb@Tw))vMJ8wultErjvHwwn5g=^%mL!oI>3;UM8qVX81qm@XV8 z%oL6jP7qEKP7zLnz9S|}0<(nK!sWtT;TmC{aDy;kxJ6hX+%7B>?hzIVi$AaKc_z|m z=h+fzEN#|%yT6}@3e$w6gyTF%qKu}lrJ~D)YlQj2?ZP7AVPT1|LRclV@9-}+M%YLg zFYGK#^0SRfkwB_&lrU2`K{(BG&}r0jEf&ocZV(o83sQ%#G8OPC&Boh{d907^qM^2E z@={@;=3h2dtogT19o6Iw$WqOlHdU#~>mD~Wd5gXYV;qoO&52W6W7p(ixQ8EU)c z`-UpiTw|y`nx7b|NOPy5iZy>T)FI8^4Ru(v)KEt?dCT#*<{ySC(RA@ukW!tXi_0{5 zpQ%EVuCCPl(@>W+`LbP=W>dOUa|E0GF?`IX?3!sd6|VWXO*u55u&Ef$bepQJ$*Zri znortPBh9DSCD2uOlufnJ0p6X8*W~@=wwkZnR0mC$O?B4HvZ(}3-fr%pIn$<+G~czU z-kR%ds;}ljn@Z8-n-POFc}r)gCf`O#)nx3XX)<=wKjxBDm%%ei2N*n=nhc(Cnhc%^ znhc&vnhc&Pnhc(4n!G=lrODWtrODXI)@1DDXfk#dXfk#dYYt{?X$}cd%QblyJ@;ci zR@R-uVABEKpUl(b<-!e`yzZK>$@_F$G>8?y zHTfFcAx+**I;`0@R2|jqAF7UP@&$qtmrn3K#!^kby;P>jS6(YL`A$WpCZqkbW_GBm z(tMNuWL7hW{~NZX-6?y?d#9pH-YN;N+<7Y19nCAHZ~az&Am_K#KewMU(}OJOzLvBr z$s!4sbO%d1-ja^9q+>1V7)v_bl2(><)urGHRr=E|-j3h4w( zx`QPhZ%M~l(y^9wj3pgzNh?db>SAz%D@nV|0a9kkD6yoETGEFs=^{(I(2_2&r1LH5 zJWDz^n0EcPG$_9*n@-o;&vMYixm<=opQY?t1({@V@h? z@t}>?51jQ@3^(c;wf9%vd-ibE;z6Nj`-B?F@yYuuyPoybeay(EQ0W=(XO9_!botN9 zJ<*RFkCVzS_e^-)s7-2GxhMN^V-cxN<=!Sw7$4cfzNo>^R7HBf&oIV?*o!LT&U<@} zHU`;AUOnr5dyMh6PUe++J3ME^8YCN(ds3b^dh7f$&*JBe?3zWD`DH&WP+jd;VBbJiQ?B4Lzz@62KtR)4)BF8SYUssD^MRI}^XUiJPo(^zO2 zA9%;iGVZb&3p^`cH_qDkRsL1s&3VIk(6GN${zz-@FWJU72GPv3p8UB+3aO;CZ@*~_ za_p^jjH@;y&-2zhMr-38@3wc0ZFYN`^SRYMFTH2! z-O)Ba`P#M4#2mzG`(ly4SQ}!I#A1B0a9=FW^WFPKt+sW^3L`7rmu2^5If&Vb*&D@m z)eYNxQB~oIS;Jne@OEEgbh8Lbtkd?V4A@BJg+7#U)FWt%5?i;>Gl|FOlm&&E09cCQg?uXbiLzjuAn>ACB3<1XWA z&oiGJC+b&Sc(|g`9p3Y0uk@^_8#S1t(0hL0n^&$?ct>tG&f1K-z5R9>ciL>TKJ>n_ z+n8W8&U?>(Y1B82EKlfOV}Nbc2Jeu)MvBe;MP+4$XZ2UcJ4Uf5vB-F$-e={9s~WYA zPY(avc5#uipPgaYJ6^dq%e%SAxZf~-^IqF;EDUMYfYVicVN&y-svP+RnNeqRjLX+z zEo>;RH6nlE_xrZ;B7AbsOKWVGuTArw z_{Mm`FbX}1hm48F>zCa3kyr&Hw#OS zdzzdu`WtOLV@?s&o|xT<#R(2ME%+Y@JJ+J>kZ2Ubz6(a2an<|B1>|H?Rhc~}?ZPb!KZI2mUJr5bShug=VqiZgu^@?Oq zT)b8j>v^eBP5YIGgDzf+Joi(Ty|80)Tyw|8G;(d{yoU^1zRg(Uong22v)Ol6jyUJ} zCd^i4S7)C5K<|yWjnBLp;kI8x!uDKHyMA2fO?KFt+ij2JddJ4t`Wp5fm8UOwKCNLJ z5>~<<-1DwCx~6S`jqrr?p4GK&t4TFF@9kU178@3JW0_O^w#@r5?uqDb z^B4_0tGe43I`@=?Udc{RYQF8+^VfEI@4MU9&Sw9-GW(2YLJ!+IQk~Cu8zkB$Rdc?5 z)_x^BBdK}8v*)fY@VwjGb{FT{Z+qM78;iZ=y=~tbVev0I)zyjKoyoR1n=#4zYhNC= z7%zGLkFoELi{f}2-!^-9h=72KhPGfqI{aTo9GiLEbysUw&vrWzCH`qi$_nPwDJR0hvDt# ze}>~VQ>gin-mligOr>;`XKzRA?LJ#CT8N_9VW!caQP&vAJ>@V3rBY`p0LR(!y>#j+ z#lS3>LB%uH8vg;N`We)p2nggKbE$7A=sW)cJa0bL%$Rt#8lSjDEydy&)DNB3*}^#{ zBreS^thO;Bj6+UpIlHjb)-O#1=`6(U!UEGznbad1iq5o~4lknqq?q8E#8|u`iwf<{ z)N}(xC1(?e8a79^iwU_Dpy7PKwFzRi6w`9g0;&m{z*nPPBVT1};dXmE8ch5RtEnoB zIz>mH<@p+-K{mZc|0_J<<8XLiJA~~JRzrw8qkE~H(vp)1tW995OgEQNV@YvCDxdFZllh^%IsjO*-m-LymGzaYXJ~?LWuS@ zv3sa~43o$2t~CulK+Ti`IL(32|3KaI$c1lHadbU&_PN$Xk^(#=1L3z|A zQvJ~0XsAz98+PiLQdwQ1tdJ|T@*69KGT{4qitv34(bE)pmg-NE8k}aLhEbH=bk0QG zpvfT9vJ2Evg=_?LyZp5$?tYaTLMlyPU8M$+%0>2q|D)O$!hAbpfiJgMOwX@Tn@RS@ z)fU9ztEL6lsppJWak(dP1j14XL(6gMuT&uQ{13eHS88V9KKNeTZV2ljP($VF1&O|f zHhe%q(jVCC7PXr>#i!a#FoQ3`x_oS!SxPM+sjUx8_S@7%53(;F_=M^Lglp~-Y6>H!nySoE7|;tPtRtMK<6IJp; zJo6>hlRn9(MF7ga zY8?NDx(HCbo3Jc4WeZdRCFM9w@%0o(l7XgG4b%gYj5Z}VQ7J5QLRx9JX!>8# zHKyH(^fjrzsT}=G21&bZrokiVIV9y-g9}E|nUHkIYKlvuS(!Z1UO552+0)C!eMCQI z@By0BalKi@utTY2gneUzVL$9pEzKQKr6Ksz4(FmX z`uiwR>@q}*!!3U4Y!I_B}gNULUmxpQXM*3S% z_COGPgQo+I-c8>Ek)mlgT}@iC<6F8t`OqZWLw6-f9e!^wJ-3~_=FIEtSpiQnQ(;RQ zJpqIsML=BI@4)U|-b;7!^{J7PGSkS{*`pSu{w~OCOw>L)f@DWj6Gi8}OfmcE(Q@Vx z-{>%{K1wH%0FHK;9{&I%=(Px@YNH2yHZ7?IQJiFYdYmqi@@LvihfdHJJryz5pvD%2 z|C<)3v4Yj7}CG;E`z}wZP$5-h^ zhzhPXP5g!4PC?o=8-DdG9SYDXn7kG^-fA+NX`ZDr zgG?pA)8iOQ9%u@DOh>n1_VIz$rr{QPI87b*G{JTmPeIyfyXk2aeN91bHhuSoUO|%A zaimCp3T*0Hk={Z=k9Mr5WhAqgk8*q;(Ll?YJ$ythj;5JBvW=;NX1rO-3)-e&hEvmz zn{*xwQ0MKYZ~d9Q3YgyS2Qwct-%4`&o?vDU<-gP9+mR7jW;cJn+T<0+?3Tb(yXiy} z6Gi&GsTuLJ2hkJ4yk?i{>{V>UmEyf}ur=CzAIS3`1!DVo$>d|nM6-JJ<#cJcdaObfa* zu@r#It4*hRFpo(x9&db)`I)?Enh?kAjb(Cpo!!)!&Mc;wu$uJ2c=0S|EF|8un(obF z0vWanh{4&u_|05K$L4l!LHy9!)NdZsyDh7+5=B!YOpDht8pLep)2;Z2O~80+iWJFgo|o3}BZ9*loY8$Z*5z06jYxo+R&Y3hBLSs-IQV6G9Y>HLpO zGsVWu_8{J5m@eiri`~-aDduw$1l&{1dXl_|2jnrW$y4~FJmv#t3ooz1NAehLn>mi} zEZ2m2jz#b#^3-$>;#C@alReE;lgIR<*=&Oc5o0jLoMQqh+WMD=Y2r*J@ zDUB|n+NI>A+PrH(PJ%|&FsgP{H8So~;{iiw{dE1g0I`rziiKLh%EehV%vYcuYpP-1 zhn3c+mg(GKUd<+BJVzd7pz5$1LTw0|nmi}?VDd;+iI9%7YMCLFWQgiGz0J!mA%InrHrHI!Sr3qO6ugtp$}pt%eq(HWElVrWL1UIRn26}NrO zgttg?#2Lf65NK~49tH_yy6N-ROae*W--*w^f%%w+E8Z|i!9QrdzDHkqHdCZ7b9XrCPY(En5cs-mvk8 zLaP|RnQwgoPZ60;iTGWx$0PcOYH>E^1)r2@>Plb*{4h4BB@scp!)S`)5MUs#4mS!f4 z+>QNQ%rMX`eClGJkb&FYM;|Cksx@3UsOjFeE$B0H!8RxAMs6}ilBgFIc5|zOXtP;C zSieyaw;&{KQV?r4Du`?dVG!XrYn>L1P$x&PjF2!f0J(loscn|{| zEyxZ0MH`N9joy$Y_`No00{PVRO&ipbRjubU?1)n|uyyyv4DCq!*A&V*(GE3GFKJMd z7J;U|CR)C{=Y` z3?ksV>4B&rihwe#k3fCEvh;HVYA;K-_Q)v`vaurqWs#{kEfT57V7xvOT?P%+s3_Ed zJd9^Wp>I50~D3VoBX2dLOZ;V|AGjV6(qxG5S9qi!VQp+Z&h>m=ArT=> zc+V$tPR)_3LQsf(o`BR@%c~I3PkPwGMDJggTfGSl7gxA?ng=LCT5t^4iVNThh0Om0 zXPO(Qr5i`X1p-#;|A9pm^#eTd3=s-1Qslh3HeAa`p2|YO>X0Zp8nzG&eW*2MACIFG zQ59K$+Ydy2Joh-Tg;WB8SeEqMG-V+21aSZ+?_jhQxI#1pZ3G4Uwjro{peIZ|LX%)7 zRKr8Opb5=Z?&WZwLV>X1=R*(&n`-z_l#o?yRYGQgl?ZiMNEI8Bz!@Mex8>Hc@_?d| zJSo3qA-dYk)75?Sl@<-;9d?&EWKHA@kY=`c8)v{3Xm@C#kYl|Li!F~+5MWPD$mUk$ z4p)8+Wma0H#!ULBF`4fgv%trSAY+2L_mFs?)P7d4~FDkoCtoeSq475@yB+ z$mQo>>r>~7d)qBTEuqQ+X}cVOaNCPDmxBX}NcAn~!((YJ;jLR9T!D~>yNpCDI%d>B zDJ^6xODzmMj!ao*(HbPg_<#b~1WQMvkI5L^H3>Dex>>EyKbRf>g(p`l;dealGYYMM z1$Jo^YE6D(`h67of^0dsis3dHH5{!f5N_g0V^D|a5HRV%^bVDNm0S=M)mFWRv5+Qq zoUzzYAZP$XqT=iLxrO-f7&IIhi@(O8Z{V_GEc$?)hwqFAIO2(Hq5yPRG^d$jFg{OFrBV(ZwHeYTg4r*lP#O>eZuJow00z1- z9|1+`Yx?{nG>rDhyrm#s{i+~5el^{gh;C6V^+Z9)Z<_XejHV+>{xb$(xoOQ*w1%N_ z%5WP4if?hsrr{=VJ|P!`6FAub1PwIY2J{}VaV7(bY>{po4`fQpHsERlTJNj0QDCX} z32B`RT{3blzxq60mx4k(*?;PxZ1{W%3IrSP-4y7Lhgg=1_WG`|j^~E_tK7?cd@dDb zv>0klf*nx0K_c#+hE}w^AP|rw-SfQAh_9xhEg(fqNJk^dHTY;c8s#&+cIJTp%HmJe z*kc9?rs})mh#4rNU+)ADLVhN|NC7>YG$Ut_L;%D7mA30$n(x2T9=%Iz*5S=F&_vd* z^B^83;g>VeQg(Eb2N9Bl7tBODs(B>7I1_DXQvmlrHPVB~g|HalnQ)yr5>J_hPK5*j z>;Y-b@g4*}0_uTq9l`+!n;;!A3A?=O)SFp_HU%rDU* zfItaY^CjvF5MPa>7oeavP`-L^wdX>~4<9oyHoqx|@wZGn z7od9by?HR7r$E@#+D&cAbsU}9C9;<}GO`uWZ9<-qDgBaKZ6qqCIX@9h=~`_>J??)5 zg|je4$&5jG<`EPYDj|~c_(X|x6K9s?LaVm~7|Ek9;gpNap>yGzBt@oui_kQRdU+kQ zStt(nnEqL4Nc&ZwzHGrMVNS+?KfyT{VazswC{Z-xx&jwvp|;GTi*Z_fF$)DSOD_g# z@xv@Mn3Q96HtOWDsILccqpJrowl5x?jrviq`ryskD5le?_HU=~SZ&6j!|&jI0Ph4? zent-4ZoY6H+p^JRYIrn0u>`GVR`NRN-la$z722dWOiK+gGz;CEl$<0Wh-cbxltJRd zI&wac?$@N{_NT7o{cG{|rAP^7f!8~~6opW(0@Kr_XatGJE=Qk`3_iUaeF0;$#)hL; zpg5n)i*B&Pi_|!eYFZ;Ue=z zLzD2pg-5SPAu;PZdVunta4YX!!j+4Meop6G9!xEyrEIL7gKjQq{&?DG`P(y6Z)e`l)IEBbNT} z*g?GH8`Qd$GA$e?{Uz5v_qEXVr|J7|&=9g!awKhL?kw*^MUwXkWyT;9hi^eyigh%f zNA@OO|A38KfVY%&L3N}j0Ry+Ys46*I^ed)CuSE%>e35_m)4D%O`2wk(L>;_G`t=X9 ziB4lgdDH@zfv%Bbd^0j$Tb~2Qm?B9K@&Q_WMWu-f3z~0}Q z^MY39x+>DX)mVwr8et_TEqdH|6cu<+kPRt| z8S-T!UA|e2?=}(t^aI+$Gz%x|@h8VnNXWQTK%0#U;vxk38M-_nrM-JtT*CcEI`fOj zH)ed|7}EIxGv@ZZkrhcSj3+$84eUAw-TNILavYkw3(q)?y5rdGsGm;Lpj??zc-f%M zTVZ&VqKM2X@=!Yp=-xcsB=*$$8A#vM3+JBp+V8*$}!w30e?0?)*#C-qeWK8#T! zHL(F#VH80nHsF996cp5>fzSx%;askTJ<=pZH!K0xw$>~ISkr)$a-gJV174kj;;7ns zT#|!^bf;xUKGh9!(6T1sO8tHd+AAR!)iYe4jy=-Sd|;q|X_H{8Cp7(EeR)#KGuGpN zJ5U?yyLvos2hvcR>T&iC!AfmEfeRc9_<2=&%3k< z@6uRRp~drEnzTTr`emxq7V{zCTp-MG$cZZlft!J=7D5yR9|!>uBts5i$QZ=R{$V8L zMbGVWV#G@Ze|iXYqS`j&m4{Ghbiamj!xb@a)D`jE>?>kH@)hyV+%W|3-4-6ah|w z8>bj>3IONE|HAnZaLjI;n}A~moOAWK{5zzXQsw)NuB<3Q?BoMMDG?Z=NV`t~vOX-z zFsWOlb}Xuw9=I&yig;gtMSPspD6DedL*iNfjc0g^2RQcuSHhcHk5dn$ApfL#qKjvd zs}ndk_9!=eH?>iiRF8Ka2KL}mBQAk!)Xs&z`FF%4guGB1Sb5>lN;!~Sm++e_z?fiY zZy3K&UMRUnO0obRehNi1CSkD+FFu8aX0-+>(j{DUZ8B1sLya`(v4Dr{NX8K1^`*Xn zA$+`!RHwiKpCroj;p0cUB~gyf)q>X9AIcqYg#>}f8=^6iDwpuWNx5S_z>|q*ytyxp ztw#`{ixWF>Kw5gV?b6Y_e?lDR8EX=PY=q`@>8v0x-2F80JptfRf!ga{`U39{;RFOp zW71-TH`j?ZUqqy!2k;4lYbG}rg#&IAp_Rckh@Tw2DZRR zeS5Cy%K*)r^P`KnA8sMF?zm8n3`W5C+~s=x93MCjyd=38Uq6pR z=y+Eeu09V+z;FQCUqGEXe^-H}#V`Ym+QLL~OOxQ~Dh2_d74LElfp-i)sdc$p!xyHU z{YhePI7xg5an)y}q}Lg=lv|nW%{h%NBo1u#1r$59zpIbopw97_mD&fSJ`Fwv)V{*y z0_*`t-aYd^c;?>KDz4E;C}mukD9>iO@AZ1)k97PGm@Posu1$hPl%7{3 z)we{dg@HA*+BhQkJA;<{3iR>I_>9_cE}PQ=RE&3=MFYHUR>gxPGV)dZoU_91Dr`NA zCb1*ExIe^DeDpZ#m^ISgdPJvss&S;<&!DcS8rF*)$^jnAY>)P8iPwukdZunTyIu?~ zUN3e`S}!WI*NbZHdQr7+y%>^vR+wJZZLmCKt2iK|JC~U#J4$TdBnFJRTSp?WMs&LB zka<3?BhWyHC(^*OSniyXs^PkG%no8Za9PeW-2F#1^8LK}jC}grfY2wlfd9}rsVVTG zl^uuL4RpxRuQp;}lW?fM<<1A7!`i8%O1-70-*{H=sLFN1*1b)EFZ_tQdIdYRA#9zN z2RYcz;Or06bGC@sW3s$+CJd+2b8?d zntwu zupKLnpegr(xDf^Pr0nkjXL=}5(@y295ZNGBlnoybj?QO=H@5dgkAHIHkfVScf5@@g z@H!~l?=fI_{e$5N7%hj7ZV~+S7)k2?~vf-r#C`7rw z*=rZIbEmGR)O!~VS9>W_7b|A~Cmu>}vf(QQ=m0gX2^$JgG&Q^l=M^?Du{>;xMvXxX3h$n6^}1MpLAHs_sA!TR`L_`?4W3nu+G)>%A%-?E zk$;)v+|*vvL^)hitBa zeJPeUEKL5zaDhltglwV#u^v$U5 z#V;9J_tIx}HizH?@N@&gFXiXs?$=NX6nbjfdky3dfQI9%KcN=@^u<43M;qHeX&{ek zxO!oI<32;ZU~eFEYAu9ALDYx}(?>r8V;%6_VuwtA7moR;PwD0Yxj0nRi6_x_^YQW< z=w6TAqlhl@BE;PlbGlv5Ck#HYZ@y}#x$8zqQBnG;1YJbRvU@BIO^c3?d_JWgsl@%QwHkEJ}dRek%)e3cQrX-<#mzBkccsU z{u>%ieeA+L%_s`T{E9-z9{9sw(TcbRp^sCmA~a`8jTWt{4QI5dV91ND=L}N}7cJ+Y zQz{yWsQc!Hh6FyIUZ}t0PJ7T`^1X#7lhNMX7(;80uG5e%Ap{;J37Vu~!wsoG@$-b2 zwUzobL+1>2@;hl$Z$`m^m9=p|@?An%qh7xnOw>bQ%{baFrRULZs*R0`}V;e^U?P$}xy@1g6zX=Sc6u(Zb4fi)9?wgNa1xOzdj#Vf$#grE`U z8vY*OJfRYvuoO*;{@ewYN}^keN6aq)7xZ@m8}v>g3+k1I%0o@mX=RtEK82b;c@DMk zIN~-6Q{H^0ATrLdAe}~-TMu89s5TIhYP0_bUnL$fIEB70oN*iV4eVBQFg0gTM&Vh& zK3=OJ)a9=UOC2TwI3;NkzDMaKm zvyyWPtzGxUD6M4C%^4&~#rMqD;7AUka0yYayU;ohsP}n|g17=`@E!{C^>j-T$j}CKx*AC58?pR%6c(1_ii7)p=~9D&NwVEL1xvxn-f#@DA8|R<6TjcEm>F;&{YGtCH!do!F@DKUfLW7 zQ|?qVzH%Rgb)QDe-v_~;Z@}^gD286bKg91pK;1)sYls83TVfRYrx0EHze+!O0a!7y zw9i5!(q1Z6F|-+PeSo51JNQQU5Px&D3 zoM8gAVJ2?<5bX`lwtmCh=p*|0&@Yv1_&7zeET7q>=S6Gh7rnziB;Xz`nbZ3 ztGM4I6hQrH$KxNN-97}UVj`Cv(>wHO$)x(&e9SyXOTpH(>M5?!Gu)`E@RW?ft&EZnpd=9H{}7!C>W7 zgQWYsFAmpJn`y@ikNe_SB@OC?C!)M~fC!E(o2Mss0>|Nk*)CzID+grqCvfB=kdq{R zxn$n-{1xJAV~*HXNyJD3%T{qb7M_5W{Th}%MLigx3055c6zvWv?iP6JkjQE8i;r7v zCh`QW^}blFf*72llj5B}CXa9lV8+4|$a+FBog;l7Fk4q?N>|~Jq zTr?r4g@PJH>+dciC&uKk1W4DX)~2j+GO-)LPG#5h*T78!^r zd#QA~ZMQ2^PiVe0GeG(zjDGmwb1;eb#jfY5wO4G--(2u%p?3`qsX&W?tKMIMUU;d$ z8e;@KtNY&B)p+ZlARqKAz~}!&L1RCu25*uO1NWmCs-(7fZY8$m4pJJDQ(eNS1|_En zp^lyw;;Vgfd~+ouIt&U(0bbnK+=SC|RkP5oehH^NJ=c)L{VX!t*@mBqW}$OEzWoel z?uSjd`56ks2ldiDaA+kO zk!7x;x_qA8vb0+Y`?`GIex2N`1gDL#oD)m|}1s>;n*qF53QGgCK;#dpnomKLLR1G0^=o%lLw~T`Ea|r|M4{%lgG{_Tn zrq$3Og5Q~)1WnR7v!O`@za?8`h;ZY7?TX-FH-^^iPX*q@DaAApdj_#D+_5N#snT4+ zJU6BmV##R)pCaXDiLp{a$eixZjDwi^%hfPy&mirh>$=#NkQbr!bqHnR z@J%;3iR?`6Vg~UB21-H7yEO}cLWe6)O9BtAmwqqkIz0IR94Eq42sp0d66U)U4w)Z( zJXjpglkX{$wVci15)`g-z0|8dJ(`6l4g2&yu~ON+x{62F#o_zn@h?_%)mQ6~mO9EI zRD%JA?-~%?0tCkHas3I?b@p_^#U}6rMTM* z)R}5mk0-tWFP&!Lsta#_fi$2l_{D`wULc)vsg2q>b@g+70`Ei9JEvw((J!@hQvGHj zLuxEKJ?L4jRcI4?T8OqyyNnlCBc=beW_qV|=7cOope8si_}gxk;8WGez&M3nP8?i= zmaCn@M^18=Lm!#^Q@f&5CzpnOeOg!XU`pDwuScZ@v}bx{^W*T<8nl+l=Di$vY%MxZ z-E?6e9&HM{LdORXr$Bi)Y(OB`m;<(mSGotdQw9e~>GvkV4nGNB#c1HStt?(h=SLL=~dFTwK( zgop7jQC~V6j!NK{=woFz-`BR98)@kWcUlPs(|HiamVl{YBA9|FK$n#Lg{F}|;a;y$ zNB@Nl;i*81`7at~0Z9&rwH?%m(_f(|57an2MG0}T5g&MkVmnke%uO?8nH4*{c8|YA|xrJe!0bhKBg8Nt0OAqHC3q4RTHQxTX0OBg> zk$d(3eGK#Yw~xVa+baLvj3ZQ^@c8Yb2e(*+cfwX!}LZs8Ipx};k}@6}7a3S_umm7?JSpedi%o19_V)4FGm z7r7hrwl7oNjgYhgGGODb8WO?KM7|$vkl$66KVVyx?PR^n$oI9eX+Z&I^;cWPL;QW& z%eyKd;4UH5rT*#xTYa}o^z_e`km4axV%7)1jr-N7;ciZF%!)aW2RqS}b{7oN=0Jpu z5mm6ik8-LwAJeD0+I5s83d&er_1RN$xYg z$ZAjlL5KzD6*kqQ4xL_z(%3f(&qQg=UBa0rY0R62PaC93_jb12!OnWrS%0+&_F>pn zT*C4u+XQK!J}X87A8dOJYLDa&aMXA!Wp;{7SkPpIweAuQH5q{l zxP)mqPI}9aOnKsX)TI;K-K?u>~X;; zH*T}AM0Y?BJM(dSMQSc~7xE5-OEEjJwQG063sWx3&+1&?n6 zE9LRacykk)9Q3E(qm-OMf4g1B>7QEWUse#SM<|G%m$64P3Tv6g4|areGMM*Sd=7rU z88!LD0F9K~%|ziNu=*Iz;Gr&%ptuV@l3cZRhm0r#Q-I*#fHPgtTs{wT4+# zJ!~JiQQQ$XX(jQKDB7L3jbgdbV?ZOM;SdG$c|+b?YszH<*Z}jzLIgf%g0M*3md-|J z`8H_WQkWpjJtvXV%LY0>u27P~1Yw-`8H_H-_~205T(2~IrkAFXAbfJpE$=OA$*tAV zj|lLVm0UK;!L(0;sq2NlGP-15WUM8Py)4c0h?;HrqPBz#`dYCDrZpSBCs8rNp<8rX;~x#Wm32$ zz-=P4FUum^HJ*DQ8(g$pj4plztcBzzm4K+bgnGHC)s`@Cp>Eo%qB;JlMHcqhq6b<) z8``Jm3_1@h*WDAiCC$FqzL!gxkJROJr_PQm^isYJZ~5kB_*0q)LB#&Zb;AgwZ6t!3{J! zfLfZ1`!Vd+gwZ0=Ny&XTwMp3K1OprJ*&$|^@T=>^+=HpZ@(DE&a>eEgY?Hql1ciB$ z!Aa`%g-xo3Tg7=wLR~R88Mj7kXOh70Bep|yIrQ5k=r;oT4Mq_9jZmxS`4}q}vf!uz zGhtrE+%pygX`)26G7-BbI=6|?M48i5{PR7_r=^TF9$Y{~)|;mqa?;)i$D0n%nU+FC zy(&#}$2T=$Ez5>ci<9I{9-tJVuMEU$8m{_P3*;R0}Z!M zxrC}_$C_QT7I$NU(iTY~tGqKDBL?MxBt=WA;qF0)>nNF$lP2q89p{kY{&IGS$Dl@O zhSm!%C%z$PBYF*Je5)psWCW*OQEKUI+sgY zC!54ENnRY;1(^x(k0X?qKpmPl~*g>XZ~+rzE4gCy6Q|R`l}$ zwxE8wI66sc8MK)&pIMr_Z0$sus;nJe=)rcQv-nhe(u3{J2*ML5uJmA&It0qR%O=R! zGC$teyJhL#YOfYluDQ@`W5~t)WIUz?8ww8VnJw7eEwcEtR>@m$G5-d4^kjQMB_Y6- zda{XG5)bi7${mm=iRe~O$WHK{s3^IE@dYm&hBYso*+EB}li&=FOW52vgUHj>mcHF; z{^mda|H|I@A7%NxWosYG!pkPg7^*A~t6H)%zyoSyOEx)H3;nok?TTDK-qV{Z-630% zMV3h%eY_!(JCKsXy%AnEf+5r#$>|LTQmCVX&=07}1{4}BQD0G*?xZz@*~h(dZh-FV zEuEf}k4Jm4BjCKrelNDmhu0hA`6L{a@o>8myb+4u#bxi}=NkUr5hP{%^_6nsB80OL z_&mmNXrn(*d3P-(>M{}WdfyjOTqW#e;aKg>cIN!do{n{%D`t+guk-Y*%LF$lPv$#) zyy)q3AiF{j>w5O(nc#_&Tr!=99d*Ub1KBG5clrwb;eXO!!VJJ$y;=QK0$yEmKP6*O zaXP8JKP_XBHt%cW)kU%{UiabF;5@Z&-b2GTI)&N4`#~@$g2NR}_IQwdb)ICFCqs75 zu7{d@@@TFkjYwakLk}OOCk1^S@L-y>mnQ~{3JjX|0Dt7een+XBakCFQoN8>s!&|XB zc)`fVR%}~es`fOEc41PrhGy zwP8IdqqT6Ns1FQ9oJ$(0w;uiAsvrcqaJerV-)fcMi2oZP-9KLi`_y`mLz%3k0(QI2%dQ z;Rk^41IBIG55`q>pB&uc^dI8zY%!53PfXk@u8x}=e9YLR-8L~jcCYSrDeFk2+1KCd zhXCVpTJ(RfIN-HV0$pY;-6ndW#EzXzx@^@?mHMe-oIi-d0& zQ<(VQ|0hWWxq|$PjDvTmog}4tqWtF*3FLfYJ`v#lm7phYb9(%pGap`0FrV-w{}AWJ zE==4R04{PWU!L8mV7yNyuCjN$}i~aqjpc$n_D) z{zT*gGa37Fq*&S>+9p|Ke!(%$+0COOv7IeU)w9_t{-J!F|oC zoaDZ4txU*_h%}fdyJPDsClAwQg6YKF88TwtJSLas*@#swASbUJX34UCmiWsVNxZewAa~ z*WQ(%xUW4cr6KKJxeR(yoqy3H-GYcbZ}y0EmYOWfGU-qvapC)&2FH(I>h#-J-&+6ZR@8d$y_4%qw>%yww=6+hXL&3$hxsYy#ufhLa=D0b z4^DmtJwf0lD+)It9lWpHI9J?o!h7(h<~ov=cn5GSQI`Ub(Ut=!G)Na!8kEqv)C_O) zYGKG3NV)e7eu-o}3VpH?ym4X{MlRHXf-gM5;A!?NPaN3RyjfH#w}?tDyphg(r|v`1 zzoV?QH%G=2ytf#`MFNlRcvlU)5gX)VDM%avSbF=0vb(8_TKq7S4Tg8yI75M}9)?w& zSPS!7xbMWCVJznr5Z%sfo1o-8dz=)G*I<1Z8xM4Ue;C_2#&-{l5qMi&fp7qVTd+uJ z$%!%<&}< z>7Zvuf_q`ws$4G)8M*)~kAu6h8T3gw9r#T*wp+sGh07sp6GukIzbwg?YImMIJ@rc(Xv4K^GLkiid`UzQ{Qhi^{rEi?#ju?_ShK@Z;y8&> zT|Ed6s&$Fy3$iP|B*O?mvEd;xup@tmXT-4YCD>eL;>`?TU8Yt{i8E-8O~Sp#I0K=n zFO|~cxc#6`scQs*CWGiY&y2wuN<`{P1L}x(r|bgkEVjh39kO=hOHz*yR8ZhD7$xb2 zh@549EBC#XUr3NuB)Ns?5>N!HMv!m+FPRAfjTh+H%n+s-*?`6_6}DzPhU^wJ3sqovH|8>E)}TbG+91w5gS<5o*@ zKZ~UK7q$?8)17UbHP=Ff&9F$54i-xoa2_lXy~DgeMV-13oeq5 z;Dt2^Q-M|Jqwm0twghn7EZ#%j-r~zdkQ>$HYoBC?At=PZTMl%!mqnTWYyoW;!26Js z-YOs7HA2w>7`EPvz%JPd^tl-oq_f1gZFo4{j!c0l!-(P5&5Fj=iU5l5bj=((zX~!fnJl`+#qyxk~^ij z{C55}2yOHKi+kq6->^$K2#PXk#Y-|CsP~MZQAebZ z+)3e;eV3maiE^zvmF#m`CofV@aj#iQ!^V(vaSsjKzdhaHQZLMiOBM^;)OmO}nBRI7 ziSaIh!y7eh=RjWB3E2SPKW{w}$??ZM?QfWiA4 zBM30cT_nho(vk$JQFWs;4Jc&d1H+ zY+&1y^=F)ku$a7`5TRk5HI3{^v;*T7?i#`N(0p6}*8ejOY>tu#MMATrIn;!l6i(Pk z^}%JJ3Yao=N?ajMk6?Q;^#XR`!x3ySKr3DNdIYFp#HP2(aEXo1703E?Hoyz{Q-%;O z;j~Kyw4ol@Xx4F+JS2`yisOC;CxkCt%4G0eiIzVh`;lt0-?C+Mg4Bk1QPW2#l@#MJ z%7ea!)?80BIun5n-{{JRdLMu)RjPHh>w#G8b_Y;P=0)5glI_&yT2r3x&7HTFsUXl3 z41n7PxbXN$nDneG8GjYYcGhnD7m}kH>hqDjktzW?;)b39bQ~a8&QRUrJA-5mac6!e-~& zl&LB5I#Ql6(DaxHQ^I?Fi78Ejz5(ZUk!oqekGsI@+3M@@qG&cWVc!bay&;4_kdy)0 zYjrR63DQ9nI(}h(C|GvGxf8-zaKcefIkq+ceOh#It@>5@nBauN%QD>J>M2~*m2Dj} zwTb2Arw?oZUnQ9;RpuBd-%Okkw6zB|Bpc$muqmS<76GwmDe>HY^e2SSTFh$M;4Ep0 zu`rbW+%w~Cqa0}A(&hkI?@hwu=3Fq2O9#(iIKg@f*Jn>JqvW-*LKTDMweWT`CDtI2!J9HE{_SFlw8edEyl+#y;g);D6mi9Vnm-{-GNQpFb zG#HGfKrD?;|9GRbjSsPv{6-K`oP_eN0x&AYrw0*5@Vl}VYiLYuN99bN7KNrsX&bZE zYqHkr-ju=#S9mJ`xS<{Mu*<0yb_KoKPO)FxX&K0a|5*d@T7aL}81=6<_CJ0J@59jt zR_&MYpp@E^=k!;eb;9`w-R(zt&NcwI0r=)4dT*Ji&5m>1f_6J&)=yo(QCC}-r%ys(0Z7w{9+y6htzC5mpqyK+5$0R_62#8#2LO>&UghNZ!R^(XE zDpsG?Y7Z2TfZEz>m1^5?SZhUF6zOt`Ra@^PwzkC!dOg*)_6ZeRFIrlUC>x8LtyKYa~Jc4ud2XJ+U4eBST()E#pKGV9Y$T&J1&I|E0qZ*2CKyw~g_rK6X$ zx_^DdmUv_#;1?+I<-VG&Y-ZWM9n7mHCD4H5JF<^Lf;QKlwJ~jvB|kVbwLE!eBcplI zDy^36NJOnV1UL9Inok*>OoOVCWV}<#>E8JZUB&xWMi;;4V~l57)N>$KqFbmvadqbE z-K%e`)~(50vwO{rHS00oS`Ti~dNBe47-FkJGt#Q&hO<^)96>lqF5Jr_NvQw5?$6PA zQMck)<7Hzz8X>=IBnjt#8b#8jZ`yA1gGQ6(=@VZ)BCKj<^q1?E7?Zb!XqKfwZ{mW; z9P1Re!0dLRUiFXTsBxCr+9~AXOkKS?LSFVi*U;mu9Q^gsWJGwUFb^>*>VyArt>Ost zVW%*|!4H0na0&0alx3I_=%CfD{=#}hI1QP#(siJ`_J?T$y>-E{^ctDQA$;eQacbB! zjtJXZ`JIoE@MtrRfD&Y3_Z<;7K-rsqZUmv7-G4;LY3)5qQE9Tx{O!j`f@)Z+)EF4! zZ8;+7Tlv9>Btnw9iJy{4#`uc&q{gHN-Yb^QZ@1dsar9wfF8;~K$uyHPmM!iO`hfZ}zn;aM?Y-PzMP;mp%K|vu{hA~m5{NkObml<^ zlF=vGw&gxO)pHgTmvyOXgk zl^uQ@)qhxoNF>|>lH%anJ6s6wHHP#LSH?n8wU{Q`A=Ek(PqiM8TJ^+AW^jjaz{!sr zLqbPXI+vnQRrlb$KwIkXmIEQYXg)#w51cPr``Fb=&?iLo@biczw(#r6kO-_)_KqQ1 zQ>HV{%8b}lzaAFJQ(505zij-e`Fj!ZTnknQMU#-=MHk@~;z(T!kiUc;rTJcEO~Bl# z8MU|_!51O_Wy&%H*O2lI2eV`H7gMg`F7qr=_5AvmKTh^*{9mj?Iar4#5AE^go42dIS z+OH>zG9O)zCPr49nZqWqkJW&C^S={g^jGQwJXXsi!q3fe79;g#;FhwelI;A4F>sEnVw*wU~1cL=U-{RS(f+1^b3#Du2H%u_P=<|>&v zbCjN;?EPaw+?Y@M8i#&bYz+HUey&s4W>-czpvwV8QEC3@R~a_JD_Ga=s7L(8I3QdNym)Kwk!o2Ib6bO4~vE* zlUvAepMf)H={s#!4dAt}8asu(z|0;4NbG9;9l#EI=~wOGE$z;FqDI$|D{V6Fp5G2f zJ$-jl{`>o9&ub9mIRn?%TbUllKl9aO6upG^i`&1Las5*<{( z&iw%m0@vdlP*^B9v)Dkd8~ZK(GBHW*Pvz00Cjl;0;{Jsme~tlAlH^AEWVrPD@aD;{EAVBA&7{ zaLJ-+1`b-}xb`>ao2d%>FvRK<>Yd8Y5P+6Cg`b@KuoM#Py9O`DB#T3MN%XgU=ir}C zA*DVY%mZOM){-6&c?tlJZSiVfn1LIh3}K6dR(R$rZ;tr`AhttKkS zoM|jfe#}Dg#|hmUP+~+OqKiMxVSx2-<(oJ%0?4vO4&Hwvc}8;e9-lptd?H!n_`-h@ zfncjk$P>Sam`sjK$aEPBUdmscNQTI2At5%PxM{G%`o>AJ-Qfrjc+qGzsX< zMH!10=oYN8?#jwAO2+J(pBH`@Y##pfQ$)ks`NpTn5bwhv8BRti|1p&JolaitcYTr) zv*aMao;n117vM8SEG7B8>14o5&1Wf|2bd*~lEWZRlsk^R1-7#L72lSHf-L}81&-D)_&Miy*_>e0f2W4U5l(q)C}5}o|JdFOPJnXHB% zkxXNX--HJuIG%|CV^$~CQJSRWm>Q*=cZr2tE!6lMqW#7%#h6AO?JWr8T|Kg-m9u+=@v?K9PIVqGd0?XrSn#V8CmO1=;! zmi~94;2{i55iQ{(PU?K`=utBKPw6C7Tj`{Q^>^m_p(^)_tUk~p*AKVoQBaq8#Y{3t zdE^ZJQR3uB%p@ZsovoZ|Pw2Ytw<;mTCl+T?s{_UCMNlD)x{_IR*@Y8qA z=vez2qiejYV%OS4-Z_(mggy`+6MBVeANJs+%`oxxFa*h|DCgHIgdL;WOT{RsLwIqYIG|Vgk=l)eV z;QHWEDX}&GnBL43(_HFM1TXUwXOTgX8yrxGoVB|k#+YH$&DWS82h!^hm`xerpVHtI z26gkBW&tG7?=*jW78xcwoI>1bK5{mU zPg+<-XOp4;_xOQxh$epb@-XvNMgkqHazZp@^RLc<+p3V?GKVZmg|Z^IFGFoEM{~O4z9d%0GBNi07-Pi;VT#rUR=0F@ zGde&6Iu$ubDw*wW;h7QW*- zveu_E77i}>4&%A2{2Oy&*5Al~G?$D8;(>^K(_Hehq@$KkpGP#N1hu7X{1rwC!=xk2KNS#>S&+0)XhYwwehgt z(O+xby6mdt@wJqKvcM?8--DopC)QGv?8QZNc;<`dk%gwm+(|GGq1DIgU{+EAqZ147 zKkek&g-eJ<`^*h!2OBw>F_=o7ZOfEec68f9v;{zNF1Qr`t-&AeGEwnds8)j%x7^vu zpjZ?V-YxjRkj-kH!Ypwp&ZHoJ4BAT~3{g6hHVy?$$%KUZ2!Md3L`q6H?H1}B5yrhn zaCfsLEyVv9qrVY*n*nx8`ApYc@i4^FYiUxmoOBlBp<2LTd%VVWf{7{s4LpcjjT#w) zGNZAQ=qMMDYmk8+_yBaqd0A-(la-AWdeklqae!qqYF^gCM7;=N1a= z4T&D%55GvFOcxim8;=9H&J-&u+`{%A`XaCq^AJJp;;mOirH1;Ls&cQ0Dudax?wLUMgjNQ)H!ByxM zPKpY27~R0T9yhiRGlGE07vLe>!ZSTI;WX_$&#!tX{WTWfIW4suQ6E5`43ucMumkIs z$B{z0__>u*5q{*#L{?43lG=q8AfW0wA1t=J0k6c9=?q#)F~J0YRBySH3qQ|CJ!W+J zbd8hTvsByrECkQ~fm6?sGMM(oLMwezdWN>b-&_UO<3^pf-Gj1y(*)S<1DtLbbUkb6 zHeK;(xyA2l`yq*Y-7Bqjoa+{ri047Mk#OzC^C-CItY`)k^N(#XzQ>hv-qqXiK6VSk z#VOn@E?J9gu`-xqF&_39v}5otfb)d@>bvfxS_6cQ=)gSznbUfFGEugP-NL{xX}c;s zMvMiV@JM+;;B+_{ zvrlHzS70?CHlGal`#+KSXXlg0eJ(B<`c|_s2A-TR`HJ~O8+CCJGvX3tu}G;PEOI)G zyR*)x^w#-5Zp8nI1R><$w}1>_FY?0|kU@PfE}93p5flBRWj*==JQ4rG0`%i4{5uQC zQ0>Jt}l-eV*9=Q7D4Y{TWzmW!r!98#sbzQ+M zVDD{NY4YY@$oS4#M~lQLe#jy+L_bC=1(EB!E@{PM@LE<|uZw!TBfUpY;^?2&xfxhe zX7H;QVVaZ4?_Wd)`0eUis>QBp;}X#W!jHsXT0~~XO>&+DJz!b50bL7RxJ9&QyDd^G zk__y~nP?DhLDHq=5KA)$&5$_wIg5#YAg9I1kLs)yD@1=od`+UK1II>MnjRsbi{G)B z42BBTcZ*3DkSZgWkeQKh-zLd0f^H;M-&VcS^Y<%~^ zbKnBdmkdO$B+$1EpJrV%4>DHpuVj;@a!(Zgk8JXUWMnr#a48A$I<;(WIE{Cbe_|JkI7kI!^EM;F|xa@37JZtN=bA6WIpw4i)q|h|zBLHqIItkQ`jQ1%L#Q zHVItNaS<7xGl3ENLJkVX=A$#I35o8I_8zzwzcBFl_h2M6M?fe3w$;F?aE}$ZM-mpl zfhKLIkOUar&I~0Y{D#wyqaX%2we%H_6a~(C8KXKiW?=>kk!)~IFq;*G&F-O)uc5EW zr|vmsi80T}j-j_?fgPN?Zs7bS?fH_qD`5>_se_I>rYz!}nf=T~;`gySvj%8#3Om1h z+H^3>8(0Kt4%j!J6EvCxY7` zn2S0Dw{Uo>1(4fxX2dj0czJJS=rhiV!-~#{2F-wST1AvccTP;u48*Tsd`r}v5#QA8 zGl@jACIVzVjRq%DHCp_gq}h(KF03Yr>qpw-VrZsiMBk1Gl<*PEozhX-pJ5ty2;HriQp7#AlwZG` zs3o1<{D;ele%vbeQFxOmE9Rl_vil>*`8|Z%7qtc@7G-8qY+m9CizxGd!;I3Lun=4z zi>Sm%@lZJE;JcQSNYgPm!seJ8L_HX^fe~_8cMl3c@QzmpGf1 ze{5EW4ETKSYZKr8pho(3am|)cY`XNsgw@P&>3n75UgMX+)Wv-edgnKcFNEC6piXz& z76|S6Lfs1rU&`DSs5DvASN+v367LKX9lh%&wEVTMu0LC3dsJL>#gLx%Ds;O2uCX!S zit3$VmLzl(PGM@dg0q_cGE(S+(y}+>dlb?`LFtz0hRn}g4f)LIj>eDRemp4rbmuSQ z-i$9`o1K6uhf^4bEC2Mww!2tQY%>}vKkO9}k(}#kaQ!&+IA)*8a>&3Jgn`0BkoK&xOA!ax8lUP`Ikf$KlxP>HFH?kBrNdG#eOHMBy+=) zL|xK%;yLXK&(e-A>sEL;@PKfll`#6)`himk1cc@qndsqY3pTv0p`Jx}63gg^HeM7{ z`Px^B?wM59DcBr4&A-9q_C3sSbHl#}_>m@0FPeubi1^3=N4TG?9rb@&6;XC;Xeu;& zp9YF(Ce>(`VM-YXMndlzxKkK?nooRgn4|~Yrs4_ceeL(yr^d=0=gGgbmWY05`XnIl0ERK^Ks7z7UE*zj-HH4_yjZG z2^>4hE%>?k1uMyD-<0k?v}Jv;D^kgnM)IGmgsXdqoBw4cdD17|p*AZt5?Jk5@?opU zRBXbzWEIg4*`tGq8UpQId{J_fEEL{7p#elVNlNoC(t?5)WU&pU{LxiJ=au7#RY)#n z8n5!#R*?__+q(YGdj3UUuOMFiI+6J(9J>q8qdh@ckRS9q`IqktF4aD&eU$rjxA3fs z&wri7DMxmx_H_%xVDEdKye+R#7%uJS$FC-%B-nL#^=dNOKgTx3v%l`=RtksDv86Wi zXIGP9hH~12P0(xQ=);46(~5>?fzd}<5{-5g#_mG7exT(PY;Bjsgj_pB7x>UM#DKjb zrmi7_LUWyL#YHipD4$C-p2Uknu|@7NcERZ6*RO%ia5_vAYoHSpb&?tU(8_zqC^T_< z@+47xipw#!`oyTVB|QkvQ;mI5`FXHDfntdiO};s?gt1rUu~DiIX&>g8$}f&lj2NAE z`QK&*+;Z>cdABH7GJ<)qIPZ@;K{o90%f_*T+5T(`GnNfj#9s;(>EdOz`5@4^zw@lYF$o zL73&%0Gry6-f*NPgwUJz-crc*i7`EV_UKiBMQ0!Fy)C`z_=j&C<;M+E3`{s6eBL6d z=)I4rBk`!L>|7|LFSf*4gTwp4X9>rfezPUU`Z^GaKLU7~kagoW?;5TcZJG_oKbFmG zQF7S?_e1t5{hkl)8kVhn`20~;nSUwo~}w6O|OXoTGZlK?JO{`)XyPIDgt9S`W(ul4vEU^k-7GJS@?q6|=X{JtLsTh}K z&Vo5M_F{kYd`wT=2}?JdVP)C(vGHR6hr%HD_B(`;>}wa^$Mi3e8wL~mL>Du>wVt9D z<1;1u<1jWaaGbXixU>>+)&}?M*Y)=7AFR~sAYbNhPKhX+T*PGjyay(K1mbX;Fn=$DV?_%)s?DG1}1Vd0BMXe_af0>SGUtf{3yX z)!XD2mbl~!j3z~l%%JA4gW1xSuOzd?*oTUbNCx zT%Tn{+>vZ%#Au6Yjd3YJO%qulW&1jXt~QFP{xj863L zF-r~Ox&IqQ0_(&)=$T3J`7AzV7~|m{2w;X%by0eBTFvnvp&yEG6KnXcH6+@!c~TH3 zhfgKaC@t!t_1!9IQf>9!>a{ffITby*5?SIdFmhwy2m8%gUVB!=n(Z@Esbrd_4dr5t1hQy<~k~ z*eck#6TwlYn1}Ts<&?Sv!I{8~;8uDPUh^(Hnhqgfao=KQbpiMZR2_mccQ@!}>gcCH z5s}y?zdvo`wBCP()3|BVycjwVd6FK@#N4ePL>Gf&2XKmFCZaC||HqQJ{*df=GtXc2 zW=b(FW?M`XSZ^r9D!2NUX={|_#X02)#=b01S#d3g6tiRfV0~JI(JH|9B6FXm|F5&v z_&-J(BK;o!i?9RwJm!1piwqkjDf!CELZ|1fH9BS#H^JtYi}kjiu|=*|l`%uM-cd2- z$xM6C`lUJS=n*lV5qE5eseUDh1&r;9^}Fo`2|L;=8qe*+Ug^^m#QC%o`n(n{ZJFw` zGUuS(;1k3l4(m14eq|Y|C1L%_oMpH&bUmv9oH9yLwAso=$x2MH&#0hrmtV|Re zq1dLZ+@0f9c@4CU<^t*vAG=;vRpQBziD|#G0jA=p3wOQKsNPPJEp0tp1=~X1a@Mb; z5l5p^JS!BuLFzg>sa9D0Dw$!b+OgcaffZ?A)>gotH`b47&sa~Yn8-9;$N}|mc6&go z0)v*KlCdpW-zaM8K7z!fVe|zt_*kXL=B`Vv#QI3u8E(o{#jE-9;2F(#R`&g{n8OX1 zTtL58j>RHXv7W`Pv3-7zexJp$BxKLKg1?kPHGB9T-)Qb%uMH?j0kQ*utda`?c-=$ zW5BObRDIhb_qzF~w6b@8+ov+dBjJ%`JG)`{u`~B1g>)h+ufontilxTkc+0;5e_0vd z8k}XEY?hkP{L6d(5Z?@xmeR$8ONi=0Gf?d}N=yIbmW^2Pw2 zO(89AWeQI$X{#%g+Ldy72_4I4d&nI$D~#>^e43F*ohfd(Ip5qisc?pEIG!rJj#Pf$ z#?0FTY0|9Z2`zHg2PO<3yL&9XhFIot)vc%3v16m!6!W_4NtI+czv(R!8GAMV1nx)g zl+^x8L3Qhqsh_od>-k;x;Ins_sAFxZOWCGlZ4;+PwvlxUN1fpBzD2@fTR=32Cs{;z4uOaYw1+aWlIOQ$<`(P^Rf@t4Q^B5F6XAwyKer+Wh>vo zeg1Jb<)h2k7XG8R!84dl&;KJ?cGTbVTciSy$cfIQrk@@SF-%NL{l+#@Slyb9c~bAZ z$m>#d>%yga992H?_c5X2i#FyTF^;#%JTcgR#GvUWwSOL*uc)B3th?)D@b}XCc~plk zr;MA*=N*>^nkJ)nDT!|Ct<&N8@~UW~Y?Qo&R^2bhw}=Y?5{pFzvVKYJE$jQ(GgTo6 zRami0(RvD#yX%?AD;&E$utT)BqD?+ZN9SNNaoQ7-s(z==LvfWEKCm%-cwi$G zD|3J3YB*`N2)GP1LhPnsNF#1Ow2+X!$>^T=1p?D+^EAzo?k3#p6*;pS*%T$RvnA87W8-mJU@P1*z)2=R< z$IbO5FNIliJt$3~@H*2i8A3#vx0P#(XA1;WKiPGEv zXm>FYf6Z24aFl|8>k^C(%`JI(f1@l;zKt1K`|$cfR%c3K%;e!1T`nDfA{A^=XcxL^2wXyi>IMn_rJE(&TA~1|wdhO?b4Xbz7}+4Ay~l!;OD;^(s7Ik?EulHWh6bK69}}o;gSXsqz84R>EBjRuAtT znN1yK2kGuN7;@P)w(L97=s@n7##QiyO`oc$T9P^6;MA093`ESO zUTn#msS&r8kFs-0q}fq$VW?iWkatp5>K2A}nP7{+#s+H-vD;~Jjzhm;>ezUwcN{sG zAAz-sKh-IZr#j_fVLDsVWXCOfsS5jF)Ag3+uq5Yy`Vmvde-1N|w2z?u#Z6C4!I8(U zy8S;7;C+XFUt=S8uu?W@lar>>O#oE9W#HsYW^VW!seQ#j^)@S8Hknmyg{t180jRg& zQS7jUy=rHCYab3i+UuXrZI;OLnx*pD&2klEOUzGAp5HP70?^)Rz2ncgI>^DCWNPV4 z&pi6~gG$M4_Es_`BmUeZVB32E8Wh$0-b&DX{PGha%Y`oYza6mbT6OEbb^10%Av=m0 znq<3^*Be`k*nRS&ns2Ry0(2x=P7&EYFZEi;V=@2x75x_R)pgj0P&zera-Lo`}mh_ zx0d#6EBZl&$>=Y~6Wh2#nlW_PF$Iubt^|xiR-`WXH;>TKv}9OE&9KY~*TnZN%6)Jy zPgXwT;U6pi^U%F=;01A7T}7zGu3>bxK~nE+b-|f*y;^68P}wyqer*BaOzYDw*JG|% z2PbizcWG#-L4zCl6k}wNmD6FoZ^hRwDpf@)9nM1~%6 z!9p#dS&5hV-9t5LwGTHO!WbesnM|(l3?0jT_57c+*|FuxU5!k1qNNeDlW;r3!fc~W zAE=4eH)aMKA~cB$W*3VQwz(_HS7>7S6)K-`ra}74*L`q~jbAXEjV;5&*Kip(>Ewxt zqTPc`V&2~r=(f59QN8ACn z(t7i~$+YWzBh?AvMu@qdWViYu?t7f#<{zU(^)^T9CpW2AXot(Y$Y*Q7t=^tS5I%I# zS3Bd@LF3HuSz-i}l|e1>f{@|lRqv8uQ}s#ow4RPOn7h(H<(9IP8NO_a$}VB0Z>&uX zz|!-l$5C*Gx(8*sF}lqnYseh#*Es3HpjqENXbEWUU(hZ8=IfSBe~H~71(Sd5LY=hR z|6kmLC7J(zusE~1KWmq$5J&oT%Wm|K28s6yDR!&-7|;+y{L~eFOjb6|pp$K*E%CM6 zQoA3+Y-<;~yP5LdXFs%`tsHrK*Z^7CAsP=`la~@?Nzpd-c4ElE|y5-=y zP|o)@ec9-X7R@Pd<2~1%za@$M4$Fz&mym3C-WrXL4E@_F8q3t=+0W45V(`2SU*9gn z`u^EdBRo-pPsu90i!-?uw}UYh58#wHkxf*md)$%Rbb{#?Hl4&YY-)AufTe(LL;)*) zviJB8_~fR#g`Fpd>y{_eQd@{s9A-)-A&1<;kW-kd)Pb>9wK+@-G5jQ|(}94f*(V%n zqYFr8h*$KJ55=SW4;xAND3@@jw$m~Gu5?D?Qye;@2!w^Fl#E5DWIjQlJ(ub;id>W( zoF&R)*kYI9#}9pvjE}=ko=#TFRv0)^j$~Zh#Zd+pSft(af44IBa3V#MdIRoKrx5PE z1^fLzDPR5`d3s8=RLQ)CK>Yx8C$C~xqPfkZVbyEIcL=4YC|Hx8&p$?EeqF-cT^_hUnx`gTcyPL=o zjU5|?NwLy)g_`J6Vq%TH1sgBJW#B28VA2k%po=ux40S-MV#YRcqip zWfKL8O~b}Ng(Oh6+VD(shLv0eH4G)Cj?yGm1B?CUH$4D|@H^viPZpZ}KyKnVhZF|_Pz|geX_Mn*` zvxO{vdP+FJ))FN%<_lm*5kyAGV42xZcj%2&4YyC&h^4KjrX1-~`%4?FEa&>s9cA_j zYq3GIsbk8~bO0y6b)|E@WdR4eg_nBx2V2N6S+_8;hmUxljFv3B$IpGAjMIlBK4Tkz z6qNn?*h?6ihChxa+4|>|i+V#q4NWQ5&7Xargb(b(rlvIg^GE2>lt<~)=js-&ck|-= z0PwX6uekZOACP4LY<}b9n?C^k=b09o;^(>aDx8fgB2#cS$I0gw5yQCEw$i%+6%=QU zlvoC(B4+`RVvS7!6~}M;md?ag|8oE5)(@gODWK@k?Jp+(ol}(8y&{ypU0B$~2X7@w zkq-oKr`N4=4^3pB@L4n9do|UqZ?03eDJo{(3-MWPOSsFwxfS|6wbMKu$`X zylpEPJ;E+rLmM!4Jasf^-vgnlXSS!d8t(?B&GOV(B!wW#sZ(#YZQ&h$_BNF117S6& z$lFNVlPYXDPD`^WH}%o|Ww<|0FZ1Y`wsVE_=|f#t!S+RqNJ{5|+th2Xg+PTCt>eia zzGE91tiF1e`cg+cy1wBqA6*PU;A-3SJN%?#l0N5aw}Ls2z#)u4APD6y1@r!=N+t(k z7{Yp|g88{e!Tj5-WS*v<$CM1|Rxo$E6wCpHJqXpU{r+1fuiLur^R{A8u#|WC(CuV2 zko50&QwQqn*w?(e9n`#3N? zA}d+csoD5lkU$WxLw>)u&r~(w%=v{f?w{653n7_Nr|=kdv3h9P zRcOa`I}gLH8eT$z4HQ(T^_~e#&28q;hL=?9aWkvI3C+7Jm_Ne3X1~u z*c-14+qeH>W%soThk=a$7J0iaD45F#A|%|^#z2^=?h6&7T(1G1BwX7q1UTd-&SEy; z@J>+@5%YHR>ip%|^Ha={kwF&qbT;DcR4UilBkXt4p6+SjLp3O9qZ{*MXz9^&6m#Dr zl%37M`DC2W!1+1!y#AJ@$@&>?j$!~{Dv-mZ4RH(}Yy)Gf%%v%%xTnaA=%rC2#knxH zt+`TTO(?-FE!v5*L86yu1(Bb-6Gw--<&~M?OmSm>7Pdh~r!10{b_tMGRq-TA zwpaM%KA+B$P>C8)Zl34^KX!PPDa%1~3SovNSd>+Jg}D3tJ_v!B_6iaAPlg0dg`cR@ zTa>7=QK)ey*Nb545@wy%8fB$_|Jrrh^X&tAuTPxmk7Bh8>%WwhwhM3k2#M^y+vF5Ky~?4G2)R_uoa6HJ7Eh=EIKxw*1SSOPJ*QZh`}C7e04 z;>_3kmCP@`y;mKyU>rG*QE?e3r{N!S^1$O4qye@^p9D#)R&n|~93gb1oh4GRP zQ`Sz#nvI%YSPS(jCF0p%1ac?`pL2Wm*=1}!v^6HRuzYnTAmk%~OJ%)eIPDaMB2jk8 ziR9pG)UO}M?G|p0hQ0CwcRERbh3$3 zeGD80j7_VRXf;UlP7j}2MMgh=6`*T3_PJmIhN8?OQK+x!{njoVKN-yZ2AqAbfJp&h zuWIZhun{RX_Q=75G$5TrJ^3iv8Tbx-bN81paA6}1%L<&S?%{u}BI8gz7rOYM9V9z3 zVzHt#aE)^G9Hg+W=W7L96x6_0R4DWf4AxPU0FmgNgIP-i?MdQ2$lV#(nB*k?y}RIV9K}P-7x~<3P;uM3`JG6W{gMBwn)H{nJNT>k=^q?gwjx+$ z!&sXiJ2QBz7#zy0b^;I=*G03tvS%J9O;9@J({_@VBwHN(Cp!t3`kO=AM1^^~1ijd| zJO+LH*!qCKP2ZThJrtIS13*@!K3&=VIL#IqetU!m-GSKsQMOOA|DLej#Tz~%p_BJH z8lXC2;AEIHy^-1_>~#EORZWT0$oA7~)?&}S3*EP^l1Nq)flVCu3ePkLDZH3pc3~96 z=U;H?evMFfPr(;|M21K{1GM5J6yepbFYbIqeqh7xLaayi5-h?z&0%?oa-Usj=%#-^ za`Hd#Ce4s*v$^@xdq}Wql`Y~vox82F4ZP1c?ZH^R%BIHd!8j)o9enV|AVosMaQer% z!S@h*`k zx{llQ3b{s7uI0QddW1C&KJ*hZNwT4fU-$`TL91+B8(;JZde;#S{t!L~YM`DtW(uxi zr5fJ~_}(7t5rQ0BZqLC4dYp^D`3XtzU1ek1=o2UsR@r($+ulnwp-tkmw{@Hy@xZuq zj=L4kjSrcA`x9Z|eLiC^(Z@4#@W|j;nT8;{t6;wQx69pp2V$@Y?;~tNNIGaCH{rn!wxqu6<;jA@F})^PBVkUZd{1 zforz4F|`kzO6Id$yzhR{xpR$_o=k%snjUoEd)^Xb4AvN?Oa?e{ZR(ag!3-w5ZfZ-N zW#(W0(JLtIfRT+J1^e^%T(1_Xj2Vn48zZLT@7OH|0>({d&!^$V7-sJ?H2aC z`Riwu;l_hTcJ!WLs{C^Cy3f?fup!ezp(CAVtH~J-Vb&RGY47(3!h5Hg+NW=U1ct!i zK`Hzzh-(!lik}F9_obY{EPsju&E86l#yys~Da5Q*;J(bg$&Wceo{5>~GUE7RR~6QU zA?0+jMpZtklDwooj3S{5J`ql~0>sb*5yAsx_y~t^(nUKQLz3j!iivh$ufG+W7)F1) zzTIl^e7kRXAl&Sx9qZOQKIkBMM%E%Ep5<2@1SJt9Qy0JMAc^p|gPKIIyn%Qx_5mrl z5C1ET(IQ-S^2$TRkkTTYb+TodSyY1?Zg$3sm>Jl}ayG&g1WLmM{lncVY{q~?{p72_ z3`{)Jd;FNYN0`K~J4D8gHez<=>xnQK5n{ov?2WSC-6=eSbM(@2o=fSVO{M%hAx6&M zI|Q9WUtV#TOq9ra`1HdhU9zZ)-*uSiLyL{F^2*@SIjusYYre;^R+2jji^vyy_?w3@ zsc8|Oar62k#3-qE@Y{}%RNo`mH#REdQMXIKsYP%Umk;Ipj{XUiP>1BxeGWu zdS-|CC&&ZzTbam9%w#e0au15@X0i?6&{;{2lQBWR{;pu2M6fg}m|qZ@5Vl?CpFU0! zf*Q2cz~PRSY^~IS7FndnyXfoUE03cS`0ToZxr%TdA^JB3vjd;G2pg{RzaA$MQI%R6 zzd>w((8d)f6)t6Jci}vpQwDMp;AV@&fAa%AC20`4>~!;sKP6)VMCd;1jMPLCIGP=m znYOBN7ys#}p%4#NJ5(fDTp34|s6sEcPqR+_S zr*{J$tlC%hT;S+7VOkdj5WoVJ%Z{Sd7ZHT zp=kmqFL$L<7>Jacge%l;UU`D(gWA7vxx?`+z6fFXzUFh6d)pPBJ3*e-JD>?hSuY7! z6-*ogV6`)t!3tw8H+9*VtV>|U#9G>DqpCXrH6pt(z{Pi+z%moyG#9V=oCJoqT~RPM z5xzx0X-!;zOo55qHk5r63=N-yC>hkn7ky4rhpk2ZNIs;n6o=5#9huDx`?Ve*v+$CfmDzUH+em zzoMvB7>ZSo25io|=v|E1i>;wFm`RgJ~@bL$KRX znOzv>qz3;>^{E`i4UDjaPfq5h;z|mhJ>C^EwYN89IYp_6{g0?xi(T+{`j}{E^?|&c zUPN}BZ;?rZYm>1>VE;scc@Rw`IvN)SCxF?U3W7+k(1sep&-)>kwIg$I+IM-8f z>pgn#MoZRIHbP#y4(fzX7r*)>6q4ui6(^zVs&()uPon$npeyxzCrO+-xJwRx zNQ!O3r``OBQzUqpU3jZoUiwh*?^0-1T0b{R%QkegOCAaj9Wvd1G2Cz-Iz#JmjZN6v z&A)bv7)IuI#Q`MnRw`3MjdUVpDrmY-qTruDM!T7ToOEkTW&ZiEYriTYFIG5?1D zz@%|W!Suy5UODP=zu3Tso+eX56;USrCEs9|+a=dQ_ZU`t54#5khb(-ke5`OP# zGV5P2iZ_e}=3eOBLXi3#KoNFY!;as#(qEqA6CA(NGV7uR04;w z=P*IsQS?muB1%)6afU?s-F;aOO_l3$%;0I^?EHIt!5K0OrFI2ej58$E5aTKlQw)S# zS(AxvLFOCT_{@cNA-s##Er!Z59XMAcNilHJPTMZ1yZFenWblGH9?gIU5EN`M6r1VV z#U|)`sO2cu(jZ=Ew6sfIF$FpOav~kg?ZOQxs9!b&e5yfAc^54^Mn_P(tvy4g8i3mV zr%j{_KsvtiED1OLOQg8xWYkAHm@b5yRMUSlGgyx!^zB;PySd!E-$0OJH!o|V`RC2nrGA6>#u^b5g75YklO+krTOd8L`Sbz zG8|r@hJs$`qcdx3wdmJEoT4RWM7L(Xx_u<_#%X2etVA7qa=cNwLad!#}x z%PxS8@O~|3u2?M`s3qehueI=ZYDr|=(q;2%_AUTtFMe!BA~k4y5Q|bscPO~8(DLlU z$K89gnUQu&Z;V#!Y775l9SI*Tp56-)K_@X+@qeXZ@_|tU|kP`*7i~qfj1cjB(oYQo`cnzcuK!vzJhV{`6lK=Q3!U$gR#c|icUwbzOGDw z)5mC2%n{jvLuS~NUhEh}w}7u`|P9GYobOoH8~wm%u2D7 zfSTDFixlp4^PhbUY^sRm`88a}j`b>*bZPSBt=+~<<(4NA70+{ zEW7~8scf8xsUe^64T+3+%OS6h(2fD)G&xlYYZ@)dD%W7}w3HR}JMZGxena%niGsUl zsWILhogE1FBa6q~7;$yQ8~{^&$`b~AS1{_YY(OA&hn&~>59oN z9|(c`U$TsW8m3#~Uz~9;E1DAc`0j5=So+mP9YVCDyeXEOgR&csOsR_KH-Cq+(yKf{ zdn4Ni{A@X9ETV9%XAY+NgMI~TDJAZ)Z(NNU;aP%=mLF?ide@k-E0Ot4be|<}a zy(9`hI+bO5SmP$6FbrB%Il7V$8J<2ci_CuA<5kY+lC^9x*#DkdHsLPvvJRnGoWrSr zzP%^x?4gBvvW9NwP?2?w^>4TaM)|s$3NeUZ{v9+qMXbjCn?NKVrfeL8Xq0Xq4E!9c zD-`=1dTS(4ODaU+O($iR9(=?s9qM70MuP-D#=|W2D)($UJVO+o#x9v)co<(b`#^Ad zFx}f&lH8(_?06(O9c@03DXp!Zs^P6Lop~u{grz!0Z}~a1@TtS=rx^n~a#vlm{Akpf=NcR2?4=MGI=ukE{i^;y)~(`T z%}de0)XShqS_n4ipT@1?Q_xNP8HO5WSe<34F@iJcaKbC={G(G}b;C*wSPR|9)9lbd zsmJ#knVr|=sooT{gf^*Zp1tq>E}DC;pZO6uiiU+$|rED3Xs)|TOeTh zicLx+c%Q%R=99jMA>f`c84?)hu(;pt;OCwrt0dlCyyYB8XK(S^^CZMqV_EV(qwQZa zu&E}w|5ctlPe%B6oMkjr5uedQ;)!#h|KxMe!^(1)|L8n+WcY@!KaaNXDJF$QoN}vT zFl&?-e{1xCl2o5!%7_kwQ8?Z+1@?_?Le||5Xq2f?w?Z z49-tP^<99?H};7B=rDupJ`+RhUaSBM5nQS2I!U88G55Hvh~gLmOY6`aX8~|1`3K+-c&Q{?d+rDrQ5oCS zTnb19yav*+HJ=Jw#~44<5trU z8&DdJx=3aBmiFF$9F8T{Wv2EkUb-n4K760NhPx8oCD>ymNj?-2;+q5&@=VhfbnX(b zQkuu|&Y^QPupf^gbGa;8v z(iRm%pCF>pw?)O~9%tj`1@Fv{D7cYtRs>wSvB|G2^mt!$;8=D{#c_4n-`~QHd&hiP z>#ZvWWg&pOkss8t(?seih=TEykzE+?gy^E0Ic^um0CvAKKgZY#$pJb;>J)~!GPAD| zV&c3TXj6f?Sgk8$h61P%SDak;;HzBpm36<`S?@$zpWb^=??LpA8+QU0l$BQ{CtrO=j573%F+F)D z(^Ca#tL@iw1Iwmxq@qC_)v=GgHIfqDo#jkH8@9%?y6qTBOijqOlib z)A;BUQM=QxVc$ailNMbetxPuF(-@<41*lAktn{z^0oFc%9CivbQFh$d!QdxUNP z$6Ebuxl+^O?EXNB%&y~XN}?>-3fadClTX!`ilf!q8e}hM@q*8+x4yZcADY3h`220S5i~D`Q{z9QjdKKO(#64yVq3GY+UbjR zh^gb&VI&QAG(dzJ-=fA_>XHGRU$Lz8(Cyx5Z1PNTO&!7!UE%z~h%KRX>OJG*V-^vn z<05oH22yzeTgQ~6j3bStia+}^8sT(if$goa&t_9ZU{Njs z60pJuq*Tms%S9L~=py!V?ICV(W2I5r#EuF~NK1PY;DzntLYt`tmKAAEIkqeKCTmBs zt-eN#gYx)2Y`!UjnyQ95?qCcB$qMRcia(XybT!T)8I*^O3(zW6S3K(EFEsj~Qfc?k z*s60O%cz~vp2`~SDkP~C;9A9l*XFSLk#cM zVg_B~Ffes3jQUmE$<~zcc_9ZtZD!$_zbA}!5qx$Eem%4dg3>M6-HDV+@xD@33F(fN z%L;4$CbV3Ebfu)4RvqmsD6xfo3>$Nxvv}fYlxIX^b@!mJF%0Z>Mup=aU7yjB``_G3 zERw31y58yW*+KJ){2_b4cg^G&yIRVY(k$H*I-I@PIoGYIMs`*(`Y$Z?R_`4jBGC#` z*nlTh9H~deK(w)USlnBWhckSRXWpIs(bc|HOE<_tf;^1%dQ=G0qRxE$Yr!L)Ze#!|F(&_$ejr|3N)@!Q}g1J@-q> zwUnzkq)L-E%UMaYj6n|MfYo*|EB~$uKdVo*qH?UKP={K9_R);DViGt6L`ps)i?&@; z#~Vlb0!xLgWI=T|AlM?U&RNFjCtI+S2bX=D8cGo2f3SL2Q&svM#QV~3CQ(@=W`)=p zg3fzz3bv96=KghCTE*(TE9EehZ7doHgURNi3*s__IS59C6$q;kauD7`$VFIR)W<%@ zYm4~4Ch)*vag$+aR#R5+wm$ahl928Fir+K#-xgR@B1UN%umMEaR^Qvw%I)}NVk7-+ za@N!le#E<~1i1=8OI%RzZ}XPa)U(yy#<#Mhz-q}`q`_%v6~8Dd4WoRjW%h8X?89pz zl43>E<+SZ+CIBBx4WpQtNtUbF_J)o87u0n=#*XL*xe_tgMh9(1L-m5K^-@@X+J)sk zC^0zVubOa6bPf?dmGn)G(e}Qbp&HF`yqlVsh(Q?=+C(&XTUXeHA_v~z7P-`Z^?EXzIEW5XVp6+4`gg6cgwL&T&b9p z5oA{M(u=q90S%r#e;#WfLnakZba$I2iCvO zU&C#nFCx7}9!qN#KJ8k!%*Q;qDT=!X{pjv`C=p~NanrPILM4>2zBJ1+82exetCPNi zM-TXBz7*sUy178V9;$Cd6*$K6Z(V{|ZM$PINB3)@UWfBb3HCP*F}np3v+5ORblCbZ z)L4@2xLV=a$=kruF}RoF9`I9j+Gku&U?qSU{vz^F8qJ?9c;L8z0l$@Bfoe6aC3qoz$O z7})rUkB+n6Xb5+O)3B%R;cxv$hMTrR@Fl#?uM)DeAdn~7eDm=6Dq}kg!nOCdz>=Zc z)FnX`FdjuJwu2?deq+~2{kvFOT$i*xiu(wYMJX3l8CJY2DY7JV+rX0kCH(;N27gFG@LrC^lZb=@bi97FGuap;=t(tOGW)hFd+5*G_d=3*-QFgJ=B*~B>#`Iwn zuQD#8PDn((vUB~NK=YSQkjOd#fv21jrQH_QrFi6>5KaAVs659p`I|s!RMn(nZt<^q zBnC)qX~e!7v}nB65MW^QCUZgO6Ba|3aswy*f9TUURHMviZ(hbs8Itr~($;3Ba`lhs z#-)6mZ{88(qMLu_HRwrRgOaY+Yf8KsiDSH5{?83OTH}=lR?pt0B>{uBrWtOW9Fmt= zHMYzz7rcXbVPMiUl*QOGLz6Z2#K*T-?B1)+&eRqYyDMPd)K-LwHG{$$|MbEZ+q#mf8ZV^N3il zDZJ5u4?3>R`MQBegS!0WI1_z$SIWV-RV$6RC=Mv|(8cvhvYaA+WuZK;MSQoLS)M0a z**Ml$p( z_946Nu-I}YK$N6C$@SIw($}erN!0Y4YP5ORStkC#c9AOsN8Y~1 zNKO>bOUz`Db+&(IE~!)rm)C}sDG$6Hqy%VO*-Bi-nC2vXaN=(evZx+V^+7R$QX3dqkyz(Wy;zew-j;oX znw8!j1*t)Bi5YIKX1N;& z4}euQ9YAIMW365YFY+kf7o;qyFn)6JAFDoF6(7zO^oeSyM0L)`qy`TxF$(NKO6W*9 z42nzOkjb2 zn)qrW8wGhc`Qy+HaCCkgv!1DHv;}^7{<$jHFN1Ohl(-)Hg2m->4)#pbu`hf3{#%lv zMgeOJP;9H^-%q;Kh zE7X<_SeMyIvrvc!8`4c_PIAAtNCj(h$R!k;gIiDY+T+Q#@4J>A?%3Ls+yN<4Ge-bR>Vv|zvTcZ6qn6}abcBaK+rhXHa2^;G2*;iNDrLxlk|T-z&_JEA}| zs3^&HKId7<`%ttnGI$yGxPy#8l6?#_$jl4&E_Q2HdcZE6^RnG6S1}s~KSqX&5*#x? zq@QM*jr`%1+mk#ZpF1RZ&9S6!ZY~nA9KoxH05iv4#xfZqX`Sp*U-h}bSuDOL35)yC zjMAj37ZKr82Fn)i&-)80=DbrsNb!}-Z7D3L(u~IiReIBBF%4;FH$}NuVzFBKc#Oq%W{Xfs_$shZOAS0m4e`X*riM-JS|1&!!wS9 zkCXXwFh0(m^0Jf6{P6373k8B~l672|@6 z@xpg@h!qZ>Lp&-+!)g|#72daM*8kQm<0crh{t+-C|Nm21^)8#M4<1-7NAbVL00WhL z0h9!29dDWYl3)!8bH2dr2rFBT`Vw%2HJ!)3|No=ZcvNVH=OK0BA>)*bDlqZ0Z_Jjt z6pg?5*CKu>4wlT&Mwr`IpU{@L!oy+UfBVkV_L@(9N@9b|)rM*;jS2c3QmDOA7 zmCj{b31smRrm2tPPsBEC5IhP>>eQ(wAYfnGZI-6OdFt_xIuDu|D0Z8TBPY8D(iOnp#LGGp&xZ#tbaoLkD1GkwqcHv8) z&oPd4XV(2x!qA9iCp*+TuN__zaV!y zqA;^WuQ(qdulJ8LShxc5fD(as+bRbAo@5)BR(x`RHk68jH9|5FtJAB>6r4T?Wk0k7(;?9dffwr ztC%3Di(N_pfyQ2@gBIIV6a8#ZXgy)2Vdj$g81OWn!XDaeQw>r)6q9TAAZ?>`B$*H-n*w7l(AdNTzg8Ir!(4RvLpEI zx7?rT++*V-cEck;FUX7e2-eO%?CO8{&plght~efL>OWrGwE@>Q?)t-a94vdvnS4Yb zB#2&df7c86xRD=1-Z@IRc}M9>O)8zNtCQw5A!0*1@C0ca{ZXYrFCV3!H>si!nemS% zRYFK~7q4r#sb*#b&4#ee)v<>K;~3+lwtfWU)<;xm2Ab(@)7)EZ#`LL!aWxMn*NZfz8&chZh#)jaJv(+t3V9HSY+s!d$dM;G5$ zMGUlb^16P&y{xdy#_J?o>4$XxeN_x%51+fQ8YEk{mR`HB8sc8H)&r)2Nzj_URC|ib zAE-j7*;7XeW2(4e(ZaIyLFpI$5t6-@iK&CCE=%^0#-GnM=1 z2ILPaxF>$sm$nwy&=(%4V);l~^gtDdKsrA>P=!Y|i-R3$YZ)~+DMmD2Kos4ehL)iq z#$|G&Qmv2POu$6($g(bz2DJbP(@LkcsHQ6>n9iE$+bt?xL`P;r)uT5(Y+ugyIC?TO z7N80iWsZyd-ujm93#Vw>D?TmJA6rx*&%T34PHlgsA{1shWzi&)2EF)|n~X3hPSD&s z3#dYFz`(H!w!Zv`;}>k02)FU}8|q?p(UnY0JgefWG(zC2A2YFsFIVSIGLd|BF&BNF z&VHyGr@aS|q5H>$5|;izH*DypxetNzF6pM9KUC>59^&i;DPEhlHF!q?)M9BH&e;C$ z%w7-T8OU_)4I7{AUBKRhhUm?Mq9`TupTii!ar^0a z=^Je-t5>Cyp>eig2pBlVV!9{p>Y=7b2z$D&ld9TP2JK0l_X>E{G!B4zo9Nd|pJ`XE zmo4q3-?ppPXdjCDp21}U3h$>3Pk$&z^-#lO)md3$5AAuZnkb9tq2oIcpVGaDW^|~E zqsw8GpW43XM80%p+KVxqom#X|fZG6@g4}Q4XBi9u+O4!X^{P}(M~N!Llj^3=i{Q6C zO%I4F@1dt-*%j`2%Dk9eEh_^XNU6>=*tSy`)d1nT?j*e=s-Bg_chewAHF9JS9%^oH z_;hfYTWKSEWU9$F7i<%5@Yd}S_jJp2z|aE>X8|r4kjoFbv$Y+)$nR=^~(K7iVq35}=2H9xYv}Fu%)|tB}T- zWrMR@EojY9Z*lft>A5adoTpuU07=%Zrr)XPU$nPN<@cP%nr1rJD)UTe-w~RY!r3od z?g&#t@1*`J`D4%;4>IXMVQBCMNa`7#XR3JUPYNunLwQ|j)?C{j|#Xfv;qCq)0ft6}xb1c)cfVpizqJCCP>$RbsSTE8cPYe?5bgL}Ziy#()F z^5nhco#RcTZBOIK(@&1j&S`+wb@MgBn-W>kq%~Hc8aIo(|?U~zG zRs{Sd*8@9gO0R05iDQ3;cMPkF3HKoy&l^RAJCE(XNS`3NyEz=}*wI45{fu-B+t-j% zkQ%UmpAv2vei=6{VSK%@Aaygvonrntr#d4Lz)gXP+82Q~dR4yW7V#$s9}*0dNDHES zRGAp7`GyqcZI^0#4@VaU-UoMmWeU3jSh0i_@xny~zH2GeCG5M7Nz5xy<9r`upmzsd zD{u0{>VR?E%5qeB@&k+s$(YSJgV`cgo6Qtz_zynG33OARQ;}cP2blN=Ai3*PMS7U- zZ#BWpE6K|nz)(#69V&y@aj0w+y4i`=rT*iVni@drMl&1$g`A@29N+*yMejLOLuF0P z1sak#zC}#y;YtdPDOPP2S8Pp@rE(=)Fn1s{RbI#yJrKX_lw^`AtuLFo2GfMW`5IN4O&9EqWHKeU}lNG4CBKxKuwo83T~2-GJ}J<@gz(m6%cOx zLBg#mpc8qLHl$VcUPxk`)%j;ch&D=`%C9`NpbrEdjLh_K^y7k{pK+?}Sb7<}N;yPbifWI=^JcNt3rJ zU~}U1q0Rbcuc}_L?$y1&+*2R-0_hZVl;KcQyBh4n zD6b+z{aPBY0kq2+_44ch*nz)c=F8BVbexJz)u^(|5pVjwI2I$gij0h2-vf=Go{ujz z-n*g1sz&W(`Wp^LRS%xgZJ>Q8e+9Lw;n5iSD;^MV(IP9pVk$LS+Rh?QV@%!izzwi> zouaXXEalJAw+NZ!fk4MlO2XO^$5g2FKZNM`O!|&PaTOIV|@>VXU{>b z(IRAlx%***YYB!%_4Jv_LMCc+hkuZCmTqx*o%bYygEE-NsXL0j%l{>DXux;=&26}aest~^AQXELt?pgI2_u-1bqLJRQ zsY@R19Az`xVdEK4v?Wm{C=1bayZ1G`WVf`~#760cZEE}WPr1+_VQW46zqx)o8?x2x zs}8~?ZoZwUmFW2WU&(dn+JLE%mz-2$&|~BD>K|@R8+my5dnb%9E^gV2g?KKUiFU(9 z>m9<4-A|l!4E^7uUDY`x+9+yHnyyLS=`$XpAcf!HFp?bfGI59ri$6*Y|m+MynmG5dP7r;U0+T zeX4^clkktV?pJPN!R#307-=&B{4bU>M+Rp;VP zKjqvCTuVQOX~(nRDj+faGTd3qfYSF*YV#R<q*V2+&YClK#;X-5jjn6x^y7!E;ZWY2(iEJj} zYxq;?x&%@>Jb{gAFctBtvUqTIeT9$k7dGvP-}Hv$Q{z?)IU=ZB+<#wPdMe$m>?31> zq_jlbFuRnwl)kuEw^vi3F5^-B`z_!~4C6yQ@*@O5E$Z5n=7Z}@7kA9)VO_f4vujt6 zXIFM#188Ra_uFsz3T{IGS$nO=K~4TOL{etOZf>7h;a=*3YVj)LDeuk-A(AZz=(ZYOZeBsqW+% z8;@m7c!e@&mk^AhR1f{PM?wEr{&M1N8_^ARE@QY+%dGsUYZqNgJ#V>`!G8rd>KNfv zr8_XUrYk@^^7fjv zQ;#h#PqT);7FWfNlqjQql7+r54bzA1buIHR99R^y>%RC=C#O4QQ=)r@H+Yw+3ql%v zi_`$EHi%<;gCluBRbM~pTl}g2rzd?1<~9V+^uqw#1-Xjde_wnPs*rq?5pTwW!}PGH z^8Z3BbuA0q`{xV(ju-5-72vhLWq%U#awGoN5>jFHE_5wU8d7UIev-@63LmD!)f?y_ z;2@I&Psk4P1wEo)H;)+4u4Vn%KWLkRQJV=!>ch;I0F-i>Mu9LLEYNL7AKm3ebS&ii zhhD@m{dynsB6%R*?q#YnOcyS2W$I?ys|Vt@y)&4#ZnqrX$2QxtH?a6a(j(#F32wr7 znY$~ytM+AbBev5K-eio|4QMSM*82CG4|fhXeQKiXy~${8o$YH=axf+`3$w0YlIUq~ z5@wzOhcf?D!3b2L$EdcWX(N2rE&~h7uF=3-j}dD;7L`){%D;z(uG2yLHzsXU+GlBZ z-mFgxUlrPJS#-zpD09fFO)z4W+hn>!@OCU^=F0i|D&yz8B`ET^@NJ38TurXaaYeD> zaaab)b3HE43k9Hig`hI$xEyfJ-G%s3npU;TI6?h5G;O7+C}8I1y~d$d`B;9O&&c-L zB)dVWw1fOOnzv@CqJC1q=pSz#43eh7Gnc^+0hGC=TM|`;$`U@m3navmh$6^lzt$Bx z)6B$r5JYeY=?$7^A}>`Vpm&}$dg9;&QgXy-ykaFKpiP=j^3L0it8V|KwEN4|(Z5;M zGx>0pvl&@?f3d0XDn9-j%+U*D!3eR7aNi=mhh*ACLwv{-89X^x`jC+xd!8t;58>Rr zUG$I-iBdF)xqb9|AM#S*nVu}T3@G4`#FZ_Q#$_GNfJS#rJ;(^?VqY>#dln0tHC9Ej ztVnBW7DqYg313plv>PdYB*ZPJXFqZf^BR_MJLrBtGKC*UfAAyE$$pk-j6azi@-8$H zZMCzo09XJYe&3!D(^=z#n_j$L@E;uvr_@io=w5#^dSqVLUHAw21ClwV?{{o1WeVJG zy`aHT=1v!jmD3EgJ|laQ-r;u8CV#N_6Ep@D6wl3KU$5Tjvz29FF2}5@iz;bmt`ufq z0GJ)n&tK(V%TVW$oTG{h(%X7fF4y|2Wf`;+KU;k4dRLH;T7E@qMx0#5wb=$J@_1~i z;{)IqwyHZVo#`R&TJoic6ke#EWe{A2R}(oiTu)9qlsOG1p-Nd~5Wb(q9b_jQ@aa+J z__UX&Gri6)@DyQcGvG)qq3QnsoA5t?VqR`?$-9nH*W@v=*kJ$GvMpnvU9VVS^*?cL zrYvNB`>X^(3fjlGur75J$NeD9sPshuQfB=Fb{;9F5(DVs%6-xb{XXfr%62%IY|SWE zExG7g>i5%G0Hc{&=ui?Qx1wT zT{Y>acR&)(N`=FBa>=fOET6?N9OM8j)Y+3GdR2AJO4(15#9%*f$y7#OWmoT*)n9_d z5mHhb4CoF+YQ)L%)Fph53ZyJ^y91ov=q07>s(IpDTvT{%A(2^M!AnDIoA7_AZ4+Mn zrEMd&&)LqW8{kZ{eioNMIfFfzM<}rCeaf7F+dhO}+KYeIBr5WMaCDF@19$Z`q~rff zHuis)&Hsc6)q&#A`LjBlniEvd4`x6B`s*e+r@wAuP%n#fo>U2<#Ao-i`Ha;t7H*bj zXU_py^@=}`4s1g!eu9<)&Ks^elt)hbZ9GZC!0T}(x@o`CZGu9p?~ zG;A&DJ(3h~i&gItqj}Ip4YaOqhhsYj>VshTOpq^>;<7$5-n=n&Hj9chk+owy<_p|Z z&&;J3kHf&JG)#bMl!cmU7h`+Bv9V$w^Q744_W9VAp2{3;?YUOH=TPg%s)1LVfMJcR zU{{TJa@9nX)o@#sc@~e3U~snhSRB$h9~JTBqDUO^a~=tKa%3ouctDjE12V3lY{G?X zCfp4C&Oy>3eQ693c-dE@7x06e#d{l6c1v4AWL5 z#*^#ablYIEO6I$r-X2UAFIM&ON8$Ci?yA&dXcyi4Vx5yv`Shopj3kQMDXdXCy*3Yv zDGyG+rRJL6=_jje6i;_4W`;lw&9x4c`{*2ErNc+3y|C&vx_1Z(ayey*cCsT?(TX8t z1i}w*wm#QSuaE8RR@pF~>d*$F;E?%1dLT;wb(bHAJpx6ik+^4LfR4u^3rug z>KdH>V%2d|scCXmd4{&?lBp<3u&zqyV#L}JCT>J4JpB}4;h84UT|{8EwN5S+xJJb348?)F4=UzXA!N<}S*SC9|zrH1=Xrt~_P)pQRI& z!LP#o?bkk~uFfW&%(BS}mfB=_&)O7^f6T&!jX+nNOFex0zJr@%F?3vv-n$UPU$IeX zWz0dE)`6O~+M~AXG)_kbn6F2uxt^{4rq-R6H70ksV-6ASiow0Uvxj5AXSOA$11rj? zKU{O0I2{n5ZxCTreQ3DQb&?tC0sBM8egsTx|0H4Pip9N>cml2(b*8(b2PS3ak*{(B zR1M*3n08rcOn0+T18$z7c;P*SWmA{6ot%UlxdMom7{b0od}a2Sx1Kzv8T1PM;Vhju z|M%YS{?EOP(i*%%Pwsv3$-O^3xwl_9*#XHp;E<0%qk@T6(^=KOirQ_V#$Yl&Zf=KB z$7;eUN6dGKOTTc*mD`D%yq!xs4~{0+yt&r%txC_Ji+}5SyF+u3v+t!9!DP?`Z4WcN z>#7pol-uR#>nV=HJ=eLM`@TViX9t4|294dscbWP!+pP}*)GQm9Y zzs(Uv9U+g<96XH(VL&>`$RS{zLb#C-N<(DO9dS`_)=p%!s5l1L!INWC+cPS**(%|3 zaNKwlEs!-@BWsEHEw_?GaCC%qR43bs-{lY#J8H?neA}C**(UXY!s*FsxT`da!JUWc zXCWk5IS8<+59keShN-ccTic(Z**3+j!A)Sz5&L-Lb+OLNbdRF6zNC)rdBc(@ia*B+^`kiuwbR4IRZjG5FU&;X4FQ ze|N>D-F|3=tPScgz`~9CFRjqr9VfUQnuylteuzKlaY%O1^N<`Z5kYIvXjoLQUH@&5 z8$c7s8qyzNu43(R8kjp+$dJll^)Mz$1M3HdGt6gaByp*RC?5PSEb3Z8>*sA!v_z7s*gVqxRK@cvo6-? z|8!NK)nR&a|2jG$oD7of?xNc^CU_vml9exMv!c;MSGctr}Y z!?Cdm>~&NdL6Y3t3bOR)9pdljxQi5CJ#n{WdqdZe{XZeZ6mu~aodbdbjmOiCEFv>jA6tSaR_JL2g2ep z1lD%MDYe=ZB@D{7ByTEacihXO-$s%dvR*wM zIGmhR91`DtNWUFUu0^agpt`0z5DtA#$MPrJ@z@S~vON;pdIS9?iUi5B474GNL{Q5Z z5;DUfHcRuWUchSGebxjMWK#&Ded2|_@hL2pd0h33w#}f+WfgpnA->g1w~r;0Wrh}dek>U;o7X}+#*&W6 z(+@H;)3;oa!fJ-u=5+i^uPjp?a){r+Zf|a%RPh3ioy6TWJ#^rBGDr5(1G;iNK6}Ok z`pI}QMgM)zG$AZdCTKv!@sTk*(O;;&H3t^cKWCc6^K&}7`sX5yc2AwBffGoizxu&B z$wPn0sIt!K@cZwzgU{1t6UgGk7zd|QU*Mml{1-9jBe5!-0k4BvhoOqaOLRqyHtmI! zOzj2sJGbLi=L~nDQETWE=U=346EF|X?O6Ahqhk@tJPx| zolu?WjyR*2J$Yx9uk%dAYPT`$=mJbJ<1cvq_ZZu|D%ElA;&pU1e=u6^!d>@lt23Ex zYB6RE8Tzm&9x?azU-mUFV?0U6eAHYH(l#WPkve2#xnpw`dx@*_)m*fnmFQZ;(a!FF zM;z#U_1uma=V$bZSNj-Js6`ApPjvlTgU|QB<6YdrMc%DV$!rn5vHd$6_q3CUZ*qu( ztJYp{ndzf*ahf9;!Ub-zC}8ac6^^Q&99@Qm8IG)lZWzg)Nw}uxiId;ZT_|rwU?6BO z4~b#-=_`{+$TMSbH3L*N;yUTGuLlpa6GCv+A@OQ6#ILH!La$##qbv!mD8M)o-9!ja zeK6Iq{hyupFw$2pa=cXzIml?ehBDaDLt7?cNhpd9y`d&{WMj`rPxS!p71^3SW%e|go z1U@_aYXSj!qHDAV>JpCOcpY~J(FIa zOd|Y`I}+Qp@`}{sJNeL&smK4`pXs)4>i-m(0@5E0G0UDJfxaT9Cgw{hipzR;2>n-8 zchkL3kr49;xZ<$>%L2)hIjXX4iTRR$0$0GrV5Sa}V`6uRA2{SriY1*FlScvG0-XVy z@|jtVg>e7#7!;2WIpZlr-GKzn7{~On1E^)@=oW_ct$wm(G=V2J7E!FJ%SqyY} z^S_j=5xY7Rq5lHK%kiE4w?5rXr%WM3V7+{93W?MI+NZ{8*?&)mb{n1qlx+eXRl6+< zjT;2cc!#@CFW&B=HB(54U)vWt;k0?ZX}EAI9TV>uKA!=d3GJLhUXSP#$MvMat!1ge z7Z*RHX(GMvYd@6#&+mJ5k^d_K7x3xeOLA2RyO`#k~yo);t44H4+!K0R)(AvQ`N1 zR&Kv>^`4f`LCn{y_uP&f5J%KScK)ITEKP4hvAn0r)hu^9ohb)enJ1`_^!H{Le!z|L zwJBAzX1|-cHSvn%7K={^y?oE@1%Khls>}C0UI=zhjrFFqy$Cs5<87CDDhjURxZ6c} zI3KPoU~29;*7@z*4PeO6Lg~bEO&X4Ga^>HEB7JwiB3-GzI8Jc2nn%wjLP}!mp#E1e zW~{>L3{^2=9v_;5b;kBYqwurjzkr=N>O7M$1R>$$+^%sWrdq>L0vSP3)(=*3I%I7R zvbm?ih7jqo?B2rZ_ick`t3IwVfr@Tz;q<~PLz^b+uq^<01t;R?wRI(pJ#nSK!=NycKzK)4wE z#^cuuzqi-Wv(v~j-i7)Y$vE?OUu0b{>`-%wYnfTG|$NqwE2u@F4su)u^{m9-^M%P=+Al!QW2+l3R(R*Sw?m1_{0d>PzQ=V?oLW55cq&AE=$FWrri_Et6Q?c!i^T4l;J7# zR*f`e;pM-BH#~s^8t;j3fa^PLW&bgVe_fB#`ALsb2UXn_XLfNIfTmYHLMD_ql(Q>Q zq*tWN`a;NYpm=vYK$(orrWpxDKfZgkLtOYI19ixp&4Gd|Ya%!7Qm{~IvDboG17_m8;-{T{Rn@k;;>Vrg8@XYp zZHGkPMni{&$W3Xfcf~`Uv@{XJv^o}E7jf)~MPSZ8Vl5N99^xv${;RS(_uKk&fj1|! zTpSf-1$@C>aYv`Ndd!AV!uz%|v5wv0eD0VH;Tua(BDXhyxf;nKuDQs<{2>l>@XpE* zXhMSKmx&$^4~c<|fnWwUn-jMtYJ{()6)@8{L={xAO2PMr&wO)YEC^G#zQjfjE>dy5 zOg!;WZc;=)vT{1$McblK*XfwOnDE3ORfm;{(nJ1ZrmrazueRt1lgB64DNykLX}NE^ zY*BNsreQ`jBdRwFpRHrd#D<68RHyBwr;{MG{rFHP@I^w$D+q9+?;B88CT2Wzn;DX^ z1%x>0IflU|p~DoqI@KZay}#N#7^z8k+TKVZ)UKAN?Xcp5zuFGX?@BsEAn`$&_Llq1 zKFD>u4EUg%d*Ocq>P(}BM}9W3xsSdikia2<4^{n7H{t0iX{ka-KB87Ld9(8Tl$G>D zfh79QK>lDuFPh%A7R~B|-Ubx(Z!HI>6W^HSaf|_KLytnZVk0y0h~y{~Nrv;N2}iHn zuD+(`YEnVVl}e4%Nr-y6!-Rqv+d|h)Cwl%@S~i`8hfUS7pkzRwqVG%v5vv3102|&? z`5e1OQPAeSQWp$WAzD`3&M8_^u;uFVMpq(ssmS z67-%KgrSJxU;(-LaR!N)oc-VPzuCg@oW8AU?sGiLf}}^%Az{>?rVn{8|y&HKwJYe+eeQ<$PrRv zudq&yca8sSprAF~7ng&0GR5==l*J0fW|d*h)Q|O+Lm0if0CUf9J4kxoLab0fL4Qk& zD+l&c?JN>+9@EQQnlgn%Daf4}cbZ|uQI)od?!AiHXy1u!{bd*5>vlyu4jt*_o11?G zIFa+K_6R=5xZv%HV@*VeGX>|hiC=eHgq&)hlJ9_loQaju#jf(|S2O3e`G?lDjgW&{ z$vV5^&6GYd7}o_C8*o=Ky)=sq_buv{!;HfP162pReF#>t&EkuFR5qJT@p>6cI7>B- zb0IM1G{Yr>E}Tum2CDKAR52>iisB3*t??Xsc{ANRn+)+%e?-dTVLuGUBLFIDk8j6zsy+YCT^pr8p= znBLDUpKgH=*<4$J#<#!ujERMW(uD+kEH}aRHmStKh5&>8GdgJwdCBZiCT-9SMr7Ie zI?m2>WzxDjW0P`qnY3Q74%sbDR=^`%gj+pHL+Xh!GdFzU$0or28OK)uAR!VD)O}r8DheHdEU)2^%1962P zuJFMXzRoMgzlba7r}GFge^%>K8U+ocQa>L5RW*D(w2{fd@QW>$h(QkMl)46__?_|+ z;BsmhyIyH+Vv}-JVv{^!QIlJ!i?w&{a3 zbA)S=IlTv`V^I~AX_aSi!x&!&l#!wFbkuyZT;|n7-=0sh_;A`gpFE`~6F<2}rzDe& z*vh&`KTjsPyqV5iK$28OU9Wi8LGu@2`D_DlZ~=*s-Rq;8g=AvTXI*UZ7^B}MjnaQ< zQygMlM&;}>&o|PPg(Pa^ZPBv}o?}3Y1ZOLY5dRnU|1xn(qg$c-p~}aWzeR#g!jil( z#lYPb;Wlt)AqkPSfMR$dX_6g#NWWP`<|!J0GNgfv$z-?NVqT|vAs>EQe5aGHTuesd zTtpAeUrbiIc|H6GoJ0Ar+h95IouLi&L98=IgAWE8x12j*Tj3Gla}m>> z#aRS>^@cUWagGmZX3PY+PZL4L_x|Jh(_|M9BHCdRUHL50%fj%IXGwC zZ#(G5rDP5sjz9vJmy%?e%|U&akrk7Dd*#Kl5|66b%|+E3c+PNG3?(`svtp!VTsv>} zF%9Bl@gxYt8clzQUcJBBVsYfINIL0>WyDwWSbVAPE=KU9^XPw;L5XrRL(P4YK?9eQ ziTZ2J%wsw^AfdT_9XIkato;LT&2KlahqoM}u%i}I7-+@^4dzB|tGEP#L6$T0We+{Q zoQy_p6FOLGInG&6n<9HJFZ(`BP3dCBCwWUG&XV3=9!n zv@(?p;yda0sbm6vR4d7NbF0`Y@i4g}+%uO_H3~{{85rF;P#It9#Is}XV0cwx*&HjR zW$GaI&Oj+&?&O27Ho!)sxgsRlevwMG;{`r;57!_rcgB9mv*MVJi&EVBMJm_ka;0Kq zBimw55+nO?PXD!3Zs3BK1tro8D@o`q*;9lIM4431B-}!zD5U3G0O_7VxZ88p+*SN~ zA-N%SOz)Sh`r|nHz|*Wve33;d!F=$6M5EH6ov(55g*I_PXB!;p+Qhk%OlUyQWAYeV z%|Cz|10xI~Jv+w1FYTNk7Lk=G>77!g>1Svr{t$B|E@o3JC-=R9AbfH^t9HgT$oz{rO@f-v+w%&Rm&T>RnE3l&4ns@^XVywlS>#?(o*m{f$_MDR#vMo{3YT-)6 zjStAv9CFyN2ePp zJZwFF@%7L_2pR8Iz6p|*p)e9~_U|q6rWAZRk&f(5Nbo*AEI1J7W&l=b%=+`yM(85k!d%sU~SJuOl#AaC-yJ!$5$QM zTbNYSwl_QKFc&&0+oct2`{UpFX@p$RG00Ujt}_qtFD>(%n%DD>x2Fw_Q|A2W z7uyufM_vpNF3$IISLA}#A#{FI@DzwDIp#!0Y=f#B&B$%$HwCh4jQdy+np~gRB=BQn zS2V}XSUHkh$+gHaPGOyw`cx}M+AnY(IyFL1@U1!4f z00)yM(jnPK2_@q8mRmNh4nmN|E-IYi0)QN@h!wOUC1O^~ZSklCPnh!SplskqPP9Ub zO@VG8?osMxcuwCI%^yiwraEzmBQE3LFr$4X>2lb9lw(bX+Vseb+tFdZjHe+~>-gP7;IEv8CM4eU$08gv;Y;<6U5HOf_`SAa&<4vR1Q>cv(dqJm3A zMT@F6%yq`BuOxNlQcTyt+Z5VC_Q-1ZQ3|I!VtPLHh$$|`A*S_Zr7#6AUg`wTnA^8k zOqvNtc`VZIisrT+W3aYr0lZvKZPFAk5q?zu=-vy0W%!t-MBf-a+YQhb_u?y3I}|2% zc%J!PhnX_8UNi!LJFb=~RU949ROpc@3&MolhjS2TD$3%P3QHk7B& zZqTw~*0FnHocH|h6t&ImD=MmO+x`Znek_1n&%^vY4MSieFbdCsJnytdXvdpA8rx)tr+(VCbC*Og!$sigfpl0p8T^bonVnGLnP2sAVP~p6F$O(vI#KO0hduIq@3zD+)0`@w zYEpOC6jK!p&fpSp$^$M^tYznGu&m6waAU1ZSBQ?mgrAf15QcaKElwwEf-LbE^-$D_ zR>cS-!dz?|h?xeclM?azeHxTO{QU;^vK82TYuXmUZg3eDJ;$mH|6Q6)XJ?SP9?d-# z!Cn;w>8nJXcb|TkL3HG7Hdp9XQbT{pAoIOH%)T)Ljx8aZ@x;Z>*mGrcR3_QPKSe*t zBtw1X{1GvUxeLfZLdm=y8HUS1f6as=L_8HU$xQwpowk+)xGJ+jS-my_<0VH|uO;iE zUz%}6cxl#4v*kI!0nOM7|NhY{<&X7gs$6A`ypZH=PL$`kI#Cj^ft=XEW$V1@IRyP%0^CFpOwmG~@{8J2UC8TZ;=k>hZ zz)0^)L=W6oU%LTCX0wLcEwY74qi*tr!)aEL@W@C!tfLfUu(MjVPZk${b z5DDi&-HeH#z?X+@hM}XxnX!|$pc&{|&Lg?bBOlwiP_-n}0}(vhw;}C0S+G<;HIx^+ z>y^TzdaoJxhK_!6{j1LF51=Ke&=R`PW)C9jNc&U(52paQGY4wfIYEe84SC=+((_0j zNP48PNGB)LvoFE0Q73ZU+(^SC(XtcY1xmwgreqvv&6m~$n`gK*tK2px=18lv6S1bb zdy)@0AiWSq!XJ1mi$UI;ko2&YM_kf1!EZ~eVh7kX(0z|bPu(f43a$e& zQ>?8-jK7B>N>X!EW~#ZcXVshs(i=~!xzR|Tr`cS-v(n8OJX1N5%kzv1N5CmBdo(wW zOW1kvbB|B1;~ocQm59GJKCpfAm*asreiFxj zYy>Pq2Wt_OTf6&i*tlZv!CaoV5VP2{NK$WQE|(3Wt+RWuMIfyn+!D~S)o6KrgIL?C zV)*1NyEvnhezA_|VhJz=Ja|g(ilyDaWwf^xgF&z`OvTlQMh2U=H{^FB4SX)3_)$ zF<+9@!3pRDd>&sq)z)9gL8ghgnhWdy{AbwLFK;w)d37+wN2UjZCM8rbz^C||o<_{g zkEPJRT%G$St{${^H<#!Cfl$UcHTDGnJF(!#+M{T za9;y^@%aB9D^7jfa4g8%9^t8Mm3z#G&-&E%h4l9g@b#KO#SK8Y|FbLH)+EmB-WE0p zw)t;QeBDqd?&*w7`P{ZZNX9Ctwr@+20#Lq2#BPHs#<}%%-|7H3R2l9LiuC8hxlw$9 zB2jsBs*NAR7gQJ>9g`}CJFh#{*Q8Y<)cDC23qc7d$4I-=c;6Z$L}3)jS&aCSi`Aao zGmugZXz#}o)!e~EdT1kAt1#KWd_X-mk;wtm*A4(c-$L(hB3WTA*ZWsgN1=V)0IMx+`8)BK-S4C7&18t~ z2zvd*KDkpcm{w7qDM!Obr23He(&Qx}wmVy?u$gS}d?3S=c^_d0-pA)g#L)k2CV?I= z*sTw5Z~G|SXjjN?Z=@ZY$z**pU=c<{VFAyxRH!xC)s4Kq(m2-2FhF3dJjUDSf~V`v zs@vN_`tMq~g^cBYqD5QCG+9kAy}5;i@b6K_77`bf->WQ)tdhUQ=n3RIdAp^r!q{|k zH*zp`DxLQ#8OeLl*Ip&h#hUEbo1kJ5Zs4^q*ne!{<9U6#ag|jC0%0!H6))Z5B-jnH za$&B8y!}n;x|KW~VzM7>GCZ{2$3<7*c__*5*%a;4w0STPb{t$}Ija-EMLI2ZQoe!r+3ZglWxkp82|f zu zFYN=VDzrI^f;~dq<~I!-IWBCUw9R0~|JMvE{NHYHDdk2CytqTRQ#ZfKdo9uoq^Nz8 zncFArHjL2ilXhuUt&0`=q-^ds_Fe~FyR?Jz$Nx9#_DMUrebSpX`=mXVebV0YebQUb z68$1OSWt(A9`*gCSUlRq>--@~5B-?SuM>Z9_!jz=!j()p^kXb9!uLrOPbe|SJl=r5 zTkf_`%Gb#>`=kPWsK-9(pe_VQ3iY8lQl!&`?30T1@PRsIvai~-k_(StjfmD^Z%CsI zz?p?H75ojT;8|su+t*hdl=OPHvVQ;1zk0z;Z4a!dG%4-gyd18({nt-z*H$dCDFlx~ zl=utJKoz77osQ>l_79yb&QU(?O7`;aG0(wpo%`%h7 zpgZDh*ch9v^$iMW*AEi)a0t(2LJ~n@)+dMI$+JK>$6PqV1#xz zm1ZhK%cp-^KNpxr?O~J`h}&l5D1_U>59nS8se3l27*86WO=c(9vHC{s=~>6=UjQwt zSYuNoa9y8xv~P051Yv1?Kw+Vv0i7pos;DtmUs#)J6j+-wt;BI!l}&uik54F3<#3elnp*VzM{=;{ncypO}*(%tBdFN7XhdbW_|rqCUji&o?(YUX>oTP)?Nta#D*n=(t_e7Pbi{EJBW|0 zt%t7IK>}rWd+6pJBxN)kJ|miW{p-dy>$&tYp2W(I z!*#!tYIZ`O-MN)6+zGp5<3pOilSD+m4~qs5jJE>%t2K^U07A$@6>yLA3QR+o6+}h< zm^)A>jzaX1og^l{XB!_1lh?6CyG)@h>ebnq9|j|TFp3(jh6_WTJpOdscn6m9xR`X(oGZLtZ3 zI{J>-*h>wsLxY*xN#A&#ESBBwqc>kCuP9!ys~^y3-hfpBO59i9ATw~pdY^vv28kS< zv9Z_`xfVf*aK8rFTh`0v70p}uNjFZ)q7BzT{-NbUB85GHSi%A7dPt&hIgXG;Ip~bt zBqnUD170Qi=&I$WWM-=m{T6%4kR)GroNr*7`bIHKqJ_Ir0|H1Oc9VIs_0Y4vN!nx` z-85_ui3whXW$e^;w~E8I<-#W@gWQPzhOiIwQ{^g<`O|fKi1#v~_9w}TjQ zVQfB0l>DD!^NCF~IB>R{3xTs5Vxr#ZN(geRg=gd_?om-TYi(Qz6lpl~GtRVGErPmQ zRgww7u??VKdVLQG3~Jhnk<+Q5@25D-tY%9cZ!931H&E?f;vZWlE&<~iJK79!#|Cn) zd$#7SSUE@EsbvDR4Rlp(9c{0T-o{6(e$Avy_mb&+9DR2$2~gBA)5;fn$&BEQSRMBK6Cj(CS2Au`Wl{q{8W!VS)O$&4>(N)hdrGGRmi0Afm29RpnUFmN=JD|96mB z)(|NuKmJ{8KnQZyI$xUf8|rTr4j32lh}H$zYW;}hLOi*v{j#Tt9fLwY`k#K`15 zv?+&#@f)b;0Ww_nbr+p@fFuuW5x8+w$=~n-?2iB)b<;x!h=KQ~zaJoz6h&fA zBOQ`U)&TZ8Pnu<8O2E6~xIRTrs7))(g{qHtd0?yY?uXQZ!%y2${7tI2X>dhh*B`b3APefZ-V<}Xj?e*l zWUw2%yx$OTX)B$Whj9>#hUfE0kZ$E!ehW8TtYx=8)Ah(%(tFXZp+Fn0=1ND?;ykiu z$T-;MxX6XIYE(LBf6sCiV|OgVxJ?pni<=}mB%c`E)%+U!ye77iSYtgxGxN!$v72EA zUbXKqWY+zfGit$dn+GBekI5Ivk?W`$ER=xEgP40GI?SQ! zW1ZsvBkWz^qAK(M@pI;O4#Nn;CFGXQFo?*Yj)00{IRc(EE%CCgmK6%t46voSyJ=Q4 zfR=e%1mw&NH_Nt6O+mY8me6+DE>?_Is{)FO41(#P=sDbGe(z_{cE7*<{(t{^jhs32 zoaa2(&-1yyKglppSHMoSWd=Qywk2EW{0c-1itPWpk{Q{&jKj?tdbjP}R)zSQW$uN>BFUFylnoR+QqkRZNKF z)(L(}6|+V1`5^y~DkjsI;?cb%(JPxsJQT%xg;Jc*9fHMUBsQwTXH5^9eih?=m;fW4 zx3FO2o9bUCqE07L+kbJ`%JJ3;Hq;VQuh7-4ytS6F@q~#d2MsJjW8{D@rpEt>gGkIz z`^#l0{3+c)&gZUVkf_s5YuA%Rz_-@^=)6vLJp7;-6E$&iQ!2biW!4Vi!cZN$$PM0v zN92***Tlt!Bc_Lslw}_=`Pbhxoy-0RU8nT^&5DP5UY1j_e-LGXbcz>dcJjlX^gHKl zVyH3Y*cnkpg~QeTWzRRF%DCEmS-5|Y;CiiH(ILp-{zW?a4PXFIyLe3v6K?4fBv}3G zdXk5I87#)BpUuB>8^IH)Ml6+M#8XWz-VH{VCn<$F-`XCbkas~5%o5%Bex{gYbHC^L1AU6T<1uaHa&84 z6n4sUF@40@`jMN#_+si4v2KXU{)4{90Q)HE(MTmdiTuSHX7od`;(dl$T?*o;qxA}V z!9-qY5x~^j>Vi5m_T4s`E zEgnCE$BD}*IRHv9+7dl`R;K?$lNGbDY=F}3$=!&%=!hZmFqJU1+5ecTE%LA?iB4N0 z#*j|I&{#V}ey8*#$)wc~xo$cX{*HCd9-79w(C$R2-Xk|FR}&urB+EQX#k`Gxt(C8D zw1^8eXsITA3l%@wd3GH&Zk*FmKqrht@ptbQZ#?>@xxPLIAevc*MWWUJ-iRA9Pol?k z3=N>ZbTt;N{)|TdNmEyUhJV#82^7%%{vGaq%hucS*-07U-163SOV`=g&F+d+Ip{~7r*{Z zxaBbY+-nvpkzXrS|}A=nd@!DXScKg0%si?4i}c_i#c z-x;Jz*Sr_xAkr@KcszRpEE(^4n+bdBY~P*^dF4`AsDScVmJGUdQe5F;x>-8J)-Ig) zJn9Ol2E4ZFXQZDJg%4mZrjXTT`NO0>S@}zuH-ryF@+zqhaKnA&vH$qxU6Fs`?@X%f zH({;FAN)I$4lJdfzcX628(@`T@8ImcA!I_>d4&k#6pMNlLki;i|g-RcvpK%?Azwr$J>pM*Bm~%ks?Q_e?%$FSJfS`Mew`cR~@RYlN0b`T`x(wnDOU<}n6G zG0=yKB6_K0qg!7jFI%FygtRNg7=FtA_acRTL9cbCx^$i?UT?g0r-(_`K{Ki>n^H+> zz6X;D?|pdIv=kBJ{O#go*pQ6wpMYJas_-idDDf`~EE`bx zMS$b`!>KDzf%>pELVvPiroEV}{bYqC=A{=&cc!g)9_EaHLN|934k`imZK8tOh7jm& zu!wIHgYXGZZxct9@LTpVkxR2;&>X`7I8Wg3q?1?U>1=FC(zNkI?C`*0Dqbv-z-}Wq zTo5--$%e(|BzSvFTjLp|qBwa~0}JvDBt4~82k)h{xiP%(%r$;+ACn3+)5-gpadZa% z^nS)Z|LvjSjy_w66sm@rsPDzt?3|bKk3h0sMeDvtz}KspYfW~@CPw$E!Z}=v@V7x= zv`wCaH=Y&?bYF-CN4^&`H7x=^$Y&m4lAihyK5th9)=OY%DfeM3HCFCeS+B;Es}Z3| zkF|+2LGdlUpT19zJ#mE@t9PVwdL+p;LLEBZC$mSmje%@~oS)hIulJj-C~U>BH_-k| z!AZ^*`JeF)3ok6{1~LJRwvR*TG9v4jyi{&$K}H|!mf!FG&FWX`hr3GBV%$Z0*Z!@( zRn*ie%V(ID0uOnwnin>AlfWT`&6fU$CQAVl?K+iJh z;GeP?h~_!`ruUh&@R#76c1d_~@J}vgENR>ezVFWu@@L*>;-v9~tvr2@nHJO{I0i^f z)1YCt^bQ>i=I0$`BJMX8k{!i4eY>gb?rtiJy%HazELHM_2bo7QZVh1me0s3;hr9wc z_!scr%-Bna@oDYwvxSUp5sU+**AEP2yA;R^wbk@^w5)U?by3Lj${Z|Qv;M>f9bzWN z+_5IX1uhu5j_G7-T)(q2O6N9a(8=!bz>-_b{f`9NDk|im{Huo;g*>9^i{;1pHx4mc z%Xud?aRZ_W$cFM4;b)-faryCvD*?#(H?w#1`!e79E535eXH;KnD#R+8*&BE8RzWIc zv+u=JwB6D>>fmP4xSARJoa>=GmRB2ZvH^Zw0Rf5oUq{Zm7R*3~STLeRoS{+JsIs-b zb$;}rAhOCc8)2XE%j)uzGF(;@sp`Q)ijuSKm>fKo9=$mnxgj}TIDD0CF>5=+MRZKU zJY4G|UH`gCit$~=e^v*1TXmOUMYXebGJ-a5l*_MTLglb%Z|YJgX%_>0BfMmDgSzbbc3ybw>ce-QHHyL{WTYp3$~-ip5>=P@ zmHAhCg_FmVxd5Q#)wom@$(&zBK!txrps%4`;l%MJDwdjobE@qfhB|VYq6W5jy}xt} zd6(mUW+Y3Q{1H=v&x{C``m>USTO`a+rcHH$ltyQM${bKnBExoxU-K90VL-fZ0Qpmn zN$pZ@42e@qVmb4QHw&%^?+!6A?bG0Fj8uzD<^yi;LGs`0*|g?ou!%1XDJb;^bZirH z_ii(ibQV(Xw3ww0H-)B;aK>bOfolq&RfQ7RZ@X!Aqlq&8LtH}BO=@I>4d>K|dVa5g zVv%Mm0HBvuyyY-+U(kGQ2=f2zdF8&0FU9!_M`gUj|NSttO4cgu>gNNFFwvG^xDP!P#b-h`V+m#_ey7*zbVCK5<94LX6XNCK|K{pSaD5Bq5e z{)goDgq5nKZecm_>C=#Yi>3=<8gvQEhoX=uftDie3;j|ixw9CECgj;-&vfndI0WPy z@#RlL<4rGV$#o1;Ak(`fe3xJz#1_yWZjtJ4@jo45#sq9}DJVlV;9svOs1qH$ zwFv10yx{}%=FRUWLgmouv^teGUQ2M5`=q0 z0_7gCB4_!OBk9Il<%Npwui+v0y}y5th4p8;{pG&^CYZ=?zcuZLSM(+D@lDz}T+Dkh zWo+qrA*LS?Cc9Zj3=*Qc>C@q0x+Z-BDiK`L#2ghBhEYEQnpFM8EvwYOj5KX)W?*Hr z7*DBoo;&<>|BhRcNWaw#JC@S92B{Ay_X%Q6f%b(`)0T0@TOX5_=^12<&1^d%&e$E< zYki4wUoE~|0047agqBXeoZGzu47jpOm^+AGAy1M7DJIjS8E)SSqT(1^xG#^=A#43b zR=ZuShs3j8tW(e8#+N4Un@~2fY?Bz*hNw@k-V88M&AAoC%n$-SM|_(_X*-Xz)`8R` z1lIOEAVwtJTabLD2pK@gFLc`JRbA#_t48z8TvtnvifMpjU z(!?y$Tf^m=P{}KyS&NXyg5Ur6UZ&44FKlB)K*T|(o z;ZZzjk& zW%o1Diz z!B3Jy+u4PR)ihK|E9IOP`U8Q2??P~{z@6qlRNIEuL^`(P> zI0P-d=MR#4nh&ZRAy`jr!%EK5`!nv*?lkLZq$`x8*(VR4&X1~Bum3a3e|@kd&qBdz z!XkWrP;H7t0v~K9u_-xgNjngcc z>sv_KzNcU+yq-5?zm-b?qJ!^`x?;l}AGQcFK#zd~}M$!T!mPF{0%y__dHHS(wVK;V<}1>bdT$P6+_0Na}1$QTp0$ zIw0fJaO)muP34r@TzAZH>wJwnctd6XcI1ei|97)qKm7mKsOg7EllcG9Bvs45M*X`% z(=B&f#QIuma0KU<`o=ibN?MQr!HRRL>`xcF*SZSlis_ibsw30Ch;Pn`u(WGT__|RIv ziEIN0|L?Ghkea`m0xE(_h_tbIFsueV0IGkx=$(RTAUtW@3(;@oswC*PK-MG<7f<_s%|U;s^@Y?-!0Sgkl98%~PQEG}^eSuCm?qUH z=Y_`5X_5hHh(&|^NTD@HM$7cn%@XT{PO1C#=cGHN)NG_Unun?Z2H%&4zZ|}kSfr~! zA6M3_H6_<4<%MeL>GXgkndDfShK+m$u^DrHf7=FvYm~J;8OP1CpC5ldxIQ&6UDQ&_ z+UZE*b#7Jn=A{Z_kFp2|{}!}1ys}GZ7XxdQ)jb*e?>-QJ_kpnL;YY?Jh;q6X2_SV{ z!jIzpwaS{lj3al;8ivbOC*%QU2i22vfzSy#XzT3*8sPN>IjAvip}p_7b~?_WRdy?+ z04RWRNJ+3%sS*hWb{}-WNZrS^BJ+>ZmhbC50ahr3oHLEP57~XXgpR&#E)^Ee$W|(D zfjd+M{C@)(;9KEn7^)+abX6FF$d1Xv{NLH6veQ#`q<1+ZK&%Msa$!@L7VAgTg)p3F zkUKckqP=HD{u%^$eoUJ&OXTqcn z`0Kw%)Af1ES__4RaLoMus!M;qloQ)dC_UH^>mS<*y`$WJDNFzadnt&hf@HJ_cuNd! z3x)1egg+K#fKQf&(#u*YO;!=P+wUYKB^PwgM^zN`DYBuJw#5B`WmkpxAxf)>Nja#l zP?bQ)6Y9GBYt)w7%LR$$bn^I$iF|4qsgzC*v<2CxLO;`4azU6d6le>uUl0<8?yGsN zp3;WL#ODaPXVg2CD+8LG9#0SdmZ=DF@d{Q%p z3#_8z(qZJ^j&Bb-l5sN7Q%)~kX1*X$Lo+Kaq|lLcOZn&@DAHAf+s7gYX79z(ODHDx5Y21kjyz)Up8@?C{(vHM#B4uWJ18d0255*>? zDkK#+oc>Bz$lOm1M1#AY*=yck0-6fO1cACmgyfPl?LblY<}-}3=l+e4B5wK~WenPg zm#wC>Gin%+r!+?-pTj-N)u+>tR;)MATANJaNyX`RTIi|pnsL2T0I$5UgnW%N#Z~~O zbdY4knyMWhq1UkGws%^MII@S7HDgNFTK5?1bJcdRT>}x8Ghn zsXYw+Qde9N{@z!}t-KOgY4Xv#tHM7$|49w6B6K_in{EPry+{30hIU-Ri7`bDaJ$RL zhr4I7^iuEN2kesd(ENVt?E`_J#*!6_mHTYUp};aVX7k4ZP0UR)rIU>=7> zo8()xrSEl64Uv5c>Z|uX-WOYkyl>x7P@QskY+hGT0XA|J2iZG>Eqz4OZ0X&)KMp5` zk-KhIH{!2&p=4dNSW{tLq9b}mEa;-t`0hv^9ud9hoVK;C9)+>|ci z6irH7j8+e$ZU=xrV;g7K!l#@D;eCKx0GYs4az&^U(>Mdxy8;V{to5wHWNxw}5Bz=aTbo<2;(D37i}RFJ7Mry z>|>R0(HQBkv#(P0$5Om!N$R{w6O(Q>9mh4*|&&YL9TB`39tI@>qhj z!HzIr&l83=YDeE4g;cq9UY38vh1`xWeuH%ZD>DiKD|of zmWw_yHD*-hRe>3b^s#A0R;5jjQPtqy(BQw{A`GgvRLt;L_Y5j6M81s~jeIZ~uohPb zgV7u^r$3_QC(L2B{TcF~*FGOrudJPxhqy7dvUa0(lp_uO0piOlG%Wh*=wwXD$-!U; z5mK)T_0W8(?N^0agVQ+{&b9a1CGHhN0W}FkXh|lrB~_t2DCG&5A-fyrzq&-?4(cNh z2cx&8gW>-x=RztSW<`31OM@s2QhQa{FsS-pOAnU>aM~x)Xi_FP3N2_r3KG;IoF{C3 z<{z#oLB^)!X)G13!t8;-n#hVX9o>0E58}0wBbUZizjc3J1O!Z@`?mG0nZn;56Wa$`@kb(ty1twzp=U#$>wH99D# zDfjo*rRG3R(H3E*yP2SGO&MF#B~A3y*VFGblZ`UXw^afv&Wf6BH4vQckaeyhfy2`{ zsuXuMR|RDsUY|`CW|&)}2yYn0Px=-L+LcXDn16Fo6S|u!#HrA`NF|blD@}hj-^RU% zn{MTiJ*qBq1Be*${93v!z=3S!{6^m{B%5$Ql$f!NB-DlhHNad=TFGHWOFM*v0}mqk zW`Khb=1Neo?*^u0vH~#thX#hJcw!Sm>+Z9w9IQ^_etM9KOMq+^PytZ@zNOw|xE*jhkU6z8%Nn@@G=KgP8aYsJtGpKh0`F<4lgn1)8cE}iX zz`yV9l&J_LxFGHhrI6TjedbhH7hC#%7Jt?zbCxRYYus)V@`z0&`Ii&T+A zCLJpO(E!Grcc<}>$lm#4nkyfOofBckn@YyT-YXoy&h)pZaiKoUS0B_S{4v=Qse1z= zAa?^=QVr$8Y!8uz^z}-c8u@eA=3{XI>l@q70!s&3_Q(5Qat-%S(&rIYH_#J*a6VWW zWqQg?P57oM2?=_>avnAXn}XL>B{Vt_sZk=#orBY_SxD)lj!%Lrk&5vghJ^rWzldsX z&#_`tSdTY};RrlwLg=Hg(^gk z{Mxj`wWi()ilpXN&xV4NV$N+fRfdNqMQx$Gw_*X^~3QxxzDfi&oL_d8#n}U&k$OPl4_JP1mh~zV5L2-uv z=;d;*mg-HWhB(6YxQAqS%scqxLJ&QXcfgXTs+eL5uAmZUHbGgG z9aa%sLr)md3O{J6mV04T76ih1;@*`qz;_JyZ7Z}n%iE~9dEA?vtUEwe$K~Q!nbY=G zL>Bk;Y~!t3>&|>X=szzCPYe50Vt%GN0m+*optHzcFmx}hMXK0lYz zZOHvC-;2Zxmfpt?W#NbnuR^MAgbc@d{cA=YBU{=dlz#@zpaHI|_!h_$5$ipC_XwK- zO^N+aC9n-K+$m8VY|s6Ns7{J^jjWlEAzj*L=iZK>;s83*R>vipbSB$u5=qf;XZ@kK zOr;SEO)HM=ggb7VuzXO;0p1?ov2U6DDoZ04XX{L%Q(Uez{0dW>HwJNOo#=0e&@TLp|=g79+q;7I#de2G;JOSrDzJXK3z%D0OX zv#$#8!;9OmgepkmG$P=L2>7oHx721jF&m%!~6#Gy$1Rix@ZLUu(e@Ud1|`7v&Eo9aEHlP>O` z#VMe#k=c+K!b!RR(67&n(@K&h9D_z(MI!UFVzee6nW5!4j5>v8Pw156Fg7POp++k` zmW)e<81J42A}wt`FWisNh_oiAiqtBz*r>$sQK`OPUPV}C2_HIzDj(4^QAU?rQGGhR z*V4Q)+bkfEv1K zPNc+Z>WD!-=MZ$Rv6z(DK&QnGrcrXX#BzJop?)(JhdER;nhj8q%cm0J0Z4zKkf<0&HeD%L>U%Lg`ARO(3$i3*^=QK5Uc!P+La?(} zh(&I_1BFl?`^<5;-gyg|8#NXjJ&iZNv(Cfe`v}+RI=49(3jb5i#|x;0pPc9NsDzVF zM_v%IS2&$uCcko?62pBE0gV6)NYpqLpZ<(<9sI#jXC+2MRu;9+p+D@@nq&^d)MUwb zj@(94T?y7XW;meSx@1+FPn)XKp%sFzTv}$4I@vZSggW)3k%JhyNx@1UXKeD%;Saf*R@28_r0L-+cX`oH$;V~9qiU$m#&O!_l=oph=L z&fU_|MAv2C!Xs22%MQv#G7eg3GTFvA2-CU{VH<0tJHz=6zW_+>PenVSHhr%rM7j-X z<7#JDUC z*OT{AANC8Z`Zs_PMV`Fq8m`A+0Zg)$t24C#m+&Z<>In)(Q#z<|3|s*^g=s@aLG1~~ zRws^#S$H8G(}KhtD*NZCK!woN@WDyu5&Mq%79Q;m8tgG8nL#)B*HCtQr^curBi-c| zrim*1Ue^%_rIh=bjUV;JfYYnYL)yR)-tjLcfnLRb^)Ke3v4Fx7hu!VMHr9!fx~N_X zO2w_kQN7lDqr0tGVTa^;E1FL`!%Wt!E&9i7|DI5P%KcH%Cq1JByIP1GNoyC2{?vJ4 zB~q}T0b<*VLH_(1CVX}-+T7Do4?JQR1<{-5299znduK-)M}{UI35q+B`|OD637<3F zV3EpxlsgNz8&dix%5#G%yOU2l%S8P#g>=8;SL_=~`&kDSGl>hqjNIxcX~3!7 zywW6+q}!Ccp{PQnA(KmB3V5oB)rauvFRu&_b`&Z2`x*@G=kuE3jdDXs^{DLcURi5a?ZZHq9ECFv z3ymZ!)7d}3gMxPV_Kny#iDSTd(eCSTuF^n~ZvwzK`FnCGiDPOO>*f+VzMHCGkx4=w zC#@*PuQy{(aRIHI{CE9FCswhC3z?%jQJe_uc4{nNQIBqjznY*Om2 ze!iduT|B*N>=hEN^@W$PWq<|s5=J8pb45yRM5>i^yan^+ZtNd^16lg(`Yl~7dk_|{ zwanwTOvU ztM;bZw};x|xubn?jSy2~=%g1iJB8W(*jeBtym$KECuxz8b{1#b7t$wQS%stK#`|M^ zFC=>_5?kks_F?rTb}w?eHvj>@_{sw0kqLurl??Zi*hc^Et^RwS^DTVH6)o87%NL7! zHRVo*2;BkYiK1q|xhLZwjD%Fe{-$B8-@7i|bHt}7p%9J1ezj%(t$iW9<7f8T50siF zXqyQ^;7KD2K%xrU39ClN$koSRYGo3m{0c7@DD1GMD!&WAl=~_0S3=y4@OMFD`Elo& zF~&X5&4q&rCJb$o!k`w~NV(&2Hg-TKMAnGH0e7QYr>$#Eqo87IfkuHftN_!ka6|zU z?4f>s$9X1URHtAiQB;kKF>wTq19lDd^KKdJK%K-t{8yA&tbTtX-lK3F1taqi8tWC> zkAr>L{rnX&&V<4JS!}_WJ{eBDy^eB=;IecD=vt)YPshpf$n%i5Pv;^KlSha~7QgiZ z{N*|YO&=XY)N;+jKfQaNn|`-Dq%e^!?aRRayA4>m9l}}h%v5pV+=Ih`vM_L#>(H`Zq!1v=vl9GhNY=5h7hqugO+6}~PcduNbaQ}7ai zv)1{Ql4Q+|9e#6dc;vbe>-7o~kDn3QY_>v2W+&lHxFX8pi@9Y@cg&Pd<$yXYLDgW^K7+C86rK<_@>NPB^4g0a!gHI5_8&p-?(zooW&^go7V*V zl11DkGZq;DypH2hLW9U}7rY-JlYpEH<$~({*VXC+;k+1+Q90hX8+IC|X|E~1K1QoU zpww!hP=3>}`m^uMI?ig+`hrJ5&4A!X5KZayG=MErjB|((? z82eIjKeP?|pCQN6b}>qGS$GkIl!(HFS^CWTIa2WLw>|=;0TK3J@tQ%kGB`rZUGPCz z#Hn$pk?YsIx;(k965KeUHY=el*y>Nr+o=t@JPRP|)985c;_edb0yphH5!F3`$IvVw z472bSq}oRGMB!T2<`SOuFqJpW7*yqOVEs3<*@lM^DNm%Q{Sshj30>>SpUBoe!1TY0qkKPQlo=_l{5bur2 z({L4F`4!!-DRSUb_nP8x_8urYV)7!ikBy>Z&aYxBT|y`@RqypUfb_VgX80MJ^tcd0 z!drMo=TnZv`}Erv5Pc5w-q)UCNf8-H(Z=D{e=_u&Yrd9j-Faw&%Okgubg`=sP3JPW zINWy$t)80@i!<;9#k&y9`U})bm{(+o-)h7y9IHkGWXZaf!*=b~MRjM?bBbO}#+bU3p~Y$~Y`h}w$F%!JslR$-5qyM&(xH{N~K z6b}eF4AUB$SK7o6yEj z!{2KBorS;lf#K|>D|C9mMWwBa(m&TE+dB=4q?f%F?EuYr-pfa}12^3*>;nqlKb&On zHw?PSIOp7@SJY+x$16xGB+aD)I*BR01RudvtYj4x3%3HPlyOMP zD4k2F8Q|+W7|opR0~_E~Fdgnmvg%<6rPkGCuw;&AVGLAT!&i9&^6Ed;U;V#al%``d z5>BaEn2wAxE+)=0eUNa`R9rKF+Rup5S+X{>Il&x`DAQGgXJCuba7WS!MCPp)#O7mg zn}rbrM3!VQ_dy5;_Tgc#|BYu?(PJ66FDtv}_?Xy`etd z@RHE!dB~DU7{g{jBv3lS8WLjsh9?sY&kJC~L0Mp#RyDp9O>%mz!1qUn4A5o}LWQx$ z7JR<{IJ{Zsp>z-;Su~ugAs?ygT*8$B61jUx_zJ^^BH~G%|`Wm|Q~T zz{4m@t||s}a2~!_mKl2-Wn+8}VLmtdzYU)pWpzb3C|bpJb@$u+cSc+6ex;)wvJz&e zrm_+dD8z^|qEzMxC?jeiwnVivxPI|Ec^Ta%v&l;syWDXv?ozSSABXonpG|$eKLo82 zj9~NVH+$p(Ssb9*rRiKo zcYxFnIpZ_H==p(r**hc$38dWRR+%kh9f3BH=wC*5zxjrE?i^``M&^Jol(K9mvc`Sa zFROI$LETK0MY!t;6KIQ$q2eOpR{D6hEqnbaectDsj8EYP!r=j5r`&m(lb11A1V-q} zVs|IDVYm$TW!HsuLrMq5zm-m;4|(gOpm}l}FN^zRZ3}Qc0@si9kzGZYQ=&F*7xwh$ zo9Gk*sFPNo5SkaNdERZI>FE@VTW43(Q$wf7_|Ll$*y0jm`vTfz7-l<~{CGdxCUazw zWoS*~7Mez2yQd5(DlrjYX`H_Az5T2$W0VRyq+Fj4X#|3JYpIp=N7OsipC~=`5k7kA zGX5v_kKv`A22?Hz`e5)eVm?@B6@t%QFx+NY5Fc?#m^<{~#dxkjt8xq@ITxlv%tJv61;;?wD~zIMOs~E3O6+i z|LSKdw~92CTps}gl|PyazH{hOTNX#4;Li>EBeR7^H#@L5n@Zr#5ykHgvj0Ulc8+gBsvA>7k zNn9DB8SqoNJ2vSe>9Ics7L4-{0b;oXOtP{z78B=}Aa{moiE0uCn7*xTI^UBnVPBtx zR6ZT8TPVKT25V+X7VH6(K?d{d3xhJdWD>Jej(e~M4I&_{vM9WmTM|7&?^o)NNl1sj zpRAPhXvi7hI2MS?66`Roawln8JZW5chj7QsIz}V}g7GCY|9CW+p6B|^@MzWNh4QPe z0|bfHltzS33Eq;PNl$kH044?-RMzb;jrVQN>&=;%EkBIUygs?j0I3ausaQ-M!sp)M z#Y8s41AR*S3RG!_*9&o&gpa@g6;qbI-%OM-=T;$KCV~wD2D5NLGB{MCM1|c9`rKYNwo|2^_d(?#=$}Q9?KxqCXYH$S71obMd|0hMwn?gO z5q=t?j{GVbCs8p#9*28nQq%pWD*llhjBe>vAmLqi#)2^;;rj**W!(U>CL+2h0SEP` z{d?189NRzu%YSPk?8qg!P7sAV?ik1uy#<6hp>;@YoErmiW){Rla-TnXlX+^&I`25M zVjtm9y*QVzni8NBq==IY!f8~yi67T>L=O_n&?Vt9{8ixZq5*#XEhaktlCT3z!xiT^ zP7XzgS9r)938F_pWD{Y&$$&~N6=VDzFeGjq1h4L$0f);o5`#qow}7mLBVw3-A0#bqjREEv8GX8p1bS z7bXsr0TrV|NE^Cp+JgK)=-&fmle_nb|93MU^xpZM8<+;!I8J?!8)z3k@~-w(6F$Ue z_cEamM~Q0i#;K^O1K0;d=W@^0nLIfTPm+bQ0A?iSy-PwIy+i-*+*?EXb)?Au6Z0;E3=>k zxwoo@8TPKKg^}JjjsPAyv8a0 zq^2daCpLjY(J?^0^g9R=P~!7Rg2c==dV$Yhj@lG8q%Zp{5zU7SIsf`+b|4ybM*#$5 zh*T9FLfD|6{froH_!drlk3Sz-4>xs+!~qa@^|yTtVy>Brb*Te{4-jDNb1(LH%X z7&oAH-11!=!lZr!rs%p4?B^N)J*jvD_fbP%p2ETGoW|{KU`l^O zT=}o!oZXNtrAKm$5$7p|o24|H3|cCGp^u3IEbqv{dA`%wfU!$~{(x%x4cKG^v%>5< zv2ySd?;ufiTtxm*2IoAmzC!B9`8*uu@OuVB zLV`h6I1AH$6qg%FUEdAr^W=7W`kzlL>~z{bGqik2WF;>-y{hr%ZtG;6hjIr~xxG`( z!bmTZ;I#aBK&l<)Na*R3?jniQ(p@AyyPDEHi^7Xg<(q>%F&!ooI!)XafL`N^Zvum* zU*go~DaxKkbLXMK9l}<0m+(Y#2R)WTj2AtS4_{Vt9{Q?A&1yt}%*9!BQCJ4;j9g0$ z8y$#s)#t@?RnS$)x-&M)h%d)R*`DlSPmbwYV$DoPF>Y`=swNN2LT2yjcx{I;V^HSG zGtu3J^ss_MpI79Hgjz!L3-9r2t3YC)<5 z(vRkJUk3h3?ocM*7*}( zY&s{Z)k?(Qr-?+*p|lZUZ!(C>5YsuK5r%G=p_Taozijy#YmLRn?+0XyJnTY>dg>f% zl*8{#jVpkRWP6y0CH-FhfQMN!#qez4RFqLexnTn)`+^HXc|R1O1}bLRve3y2B+j}Z zZ0#r5%4AHWoWgcP_+pTs;ss<$8`3HAOTEkleXf_Z>MX)6KZt<1K&{U_Bg}yV7x7!4 zdI(7s43Q=YLJTJzs^sgvOo&nNkQALt8_|69c&IKUtnKonv$|-dr8oRg444h_;`sg; zE?G;J55IQBpfrYt4@{e2=-VY@kIF8B;oa59hNqSa^RMA0*4)jc>8kSOW*uA*u0bVo zPKfAV5$|$d&MQOWrVzK1 z@#89*eTl|Rr0|ZEvZ)fcmtP`fuLlo$sn~gF7FcX93geN|&o7a&iIN@k9p1y%?B=+)sGE@oKQMQrbJZ*rVIYEl%&!W>Sjrh zVk{l|l=-}nKExmOV{9Le4q^{5K(#Y;i7G1iDgf)g_WMqFL z#!{O%BHHwu4{jSUa%Y5hz0!E8 z(}->RS1(`U&%SJNdY0iBSJ;w(5!pJV%Ud=|U!Q|`PRRgJC1TEHE6`fZJ~Vl>-~Nup z>!8#1^XYW`Dmq3Xb5i*M1yy4k_SHFF7sdsYP?~@$RhgORKX(cvA(9Ws5l>EqY*)L;ztq(mrQ#MnjAN@#zG-*qj*CL9Yh8W;3F{Ff@xXq1=q*3(=z{M4QVJfDh@-gLH4HyX8G8Qerrn#O)VjR{P(sdodNBvOhO| z4+p1n;(?3)w(rH%HXx<>cdul1e-{(#5;qmBJSi@nbW+STo)qVNeo~x2>!i2@pXF<& zAj0aKe!dZ}wp{m4ajdRiWM*}*=Fj1RmL-7$Iyx}LvDh3H5%J0_w~UVX%W0si8B+GA zUu;oV%|E89zQ0~xLj$}v)}X9i59c{YF@neH02BfaBD7U*r*!h#$GL@KX5j2-y4y-m z;GX0{^WEWe@|>huqHMvs+<22M{dNm_^eEhWm&~GP`2Fl(6I308vj&#g86K$9S4IoY zK(Z5!RHD(ntXNqShDh6}3ZvUxtgfD1L&Ga+L-C6y@CO*8Hmht5oaFdJ0qnGKs@WAt zUy~{4MXKj$9-Nknj}+L_34#z6o50E17K<}xknhcWP#`;zR`Ig}*^!ow#cp^8yvC8x z4$8f;_zbcz{+SD{-VRs!rI@yn150u8UleAEp)~*?AG;SxfxZFnwO347{SC%~H1nq- zImm@uSmVXi@4n}9`(+V&itzzq*3<4ci;jyL^-_+W#8Ts$p>+Kv$%TS0bLfj-33KR%I1AZOD7S=VWd*z=1WpNz?gl zs5qQudsr5(RaxeOouC+@6!v`lh}Lub=W14G{5Zdak^bBbJuhIyi#Oy|%P0LpY8oT^E$jYLhBB)!Qwc~?7tCrbALPaD3N9bn+6>3?s&ve2v42md zjM4>T8Oz!hiZi0OV~y=8qLaVxme9rN+Du80OmY)ExHk!(gfNC@iSn@R0i{b1RQ$~%a z-S2OtwHVYaqW%Quk^P|<-ncxv%d9V7k@=w*S@J~q_+180U!AZsh$9->AH;2qa49rK zRz&Y=5k5qsHVtg3;|8J-+(^6GjgN3d=9}AuMrVgrje%D@vIGmL|2m0jKkSt63gIHeoIj84s&}n~Ar)bmF z(39C78G8^&B%@wy25rgWqH7=K!m9M#^@xS={@>o2MNPxGHre}{1sWZHcv9?z6Alex zw4*Q*fpTD{AldHoZrBpyE)4wDnP!THPUws<0Eb|syK7SvBCx)1TK}YmI}4Nb%6NGL z!o?bCZvB%gQ4T-YGr}NBe$o_$J-;$QCd%7B0EBQ7c+sa|gQDE8VU-jh4tTZI@^9*e zBu@wBBz#>-$Wfr}Nd6>@R_N~U#REWEetF0%e19C9emAY#g4q415lWo78&hN;fDesU z6`Ew}-FASK$gKJVD;oaXM%dEV?!&dEeeJdv;dDOpcHx0f&E+6ct+?KB;J5;IK1=V5 z{EhqANuW*w*x)}7ZOA){W_{74k?rZx(A1cuepzpD zKkarH<4fP>-b>%xun|-Jc4O<+c-^Ut=8T0`E{LZ4j4=T=DsFwIyrLVvKVG5Y6V4a; z_t&D~OcXB^agG%2hwahOCASHZzUcBb9qGO1Q0+(XtYB?1P!Y5XI|uckV_{g*?ZOC; z8WyxMG($?b34KOX?ChsZLUMP4GhwPiO*Od7P2_LTdii z6~{t_+zh+KM*fiqHo~%k3#(>zS{Oa9nNEr-BausofW=4_ZJccdDAWuh5*X`TghhCz z@XS^9vpAKWRaL30=@gDH^~6`^{{@RoY~6mhb_vpI1gmq%E*w4C9}hJMV1u0<%Jg(P#O}J3iN+$=un;- z+bS-_=ALhTfD5f5!se@)p%uglg><@2xB*3OT2q^;T&!}>jHhn(Si#7ucK2wcjaVG2 ze(BA`e!2&AAYkq6y$wN}s-LprC+)C3RA zYR~vBgHRQ`boQr*@taPP;g5|KszY-cGjGn)w&MDL7;iiPWa_Z0lVYs;?9~AJgTA;d ziP7IUbNmMl2Owt8RFP(rP(ku+R4b+ZntK!qbvyTYk4Ew))^R*muOB};ijAPR@zbK% z@ekA^uvpzFhb%j@SN48bRY=XN^V};oWPX_~h1>S>S#Qmrbu+{I(xW7XcXgwtB%}fa zA2HxmTu7~!-xI}-jhND8NO^0v@#YtWWTeQ5m5V3cZNdotauhqw66Jzb#6Wc$v3My> zsC_Z!aY65n)jf!%QzIJMiv2SRsWI4RfhN_~0y}0{#%T1OeO6lo?nVsDf*MPG9{%gy zLNM4yYhyhX0z@~BhJyY{TfI1oo~+%q$HmqX8;_2A070IFe>@G~@@+mptadDLRaWG#P~c?~ z?)k)Pp@d8;SvR1f`J(&T2^Q8+wTv93MIxcdH=X$= zP-9JUABz+;-Js8{U|_0dcR00NfUR5DHH3h&ddl=GVj|T5exmBmx)M2U%^$!Mn0Bu< zVe?9)-T#nAy+Y~tICFL&0-*PW1G#1@vD683|M5ib58N%+S(LWcMQA@Uho)5$Ch!y- zL?7m&eAg%Y(<~1lvOIu>P@-pTs)py?wCs7eQWorptdx|4VXvS;?N9XaH(_naI4hKk zS6#tX6*{&$iyJ1p@kW@@?9mPoV8a<joT!ze$fs>R(T>hsra&0uJCm8zFc0o!?LZl)k$(H(eNh#Ep!Bx|^;OYRI z4uS5&j#$L0>NQE3Pft1QRCPi4YEW;wK*y<13PhH|n9g+77j)o@svS9t6b!ox;r zS=g1ywwRCOj54$%X|PxDJ4TgfbIPi8AU~)o>2kNQagc}?0DU+bT{9mMSt`T62*Q{i zKxx${tzaF$;qn+DOS93P=$$Y4;A*%BX02R3&i^P&bm^0?am*)Vv`xx;iHl2UH_# z%gG$;pv%j|@F>_JcU=~K@(wq4ny-DNJ~}44Cfcm(R>;SpZM9xvsZOwX_iq~h_Ag;RG7KXc6<)2$`=N2_3#p=0CX~n7qU};~ z(Te3N)5IP=+(!Z4opO)c$iJ*(BQ0Ycif%s{Rel)?Py_-^sYyT6Oqb32KXm;GTvXNn zKaSr!8<%}p1O(K9K|nzrg_6{CWVvc?xMXf6DAurOxKy~jodH~OsYuX^fM99w6gN;y z(F`izrCGfPR}dGJWE9kfMbBlM`9052z59M1|Nn!>Fmvxc_uO;NJ?C{^>+^+q=Uxy{ zNVU8TWQcWLN{vk0a@SC3W2{2<^cJ7F{x zK=j?0$^2=gV$9RBd+)ZA;b*B>C#&@21B5<7T!_8`fX6ha3(l@^77M&d4&zq@@O|!eYN7C{Ay0ck z_`=}GlXMZq^TE1B{#Zikqu{IB4cOO+3_3OTx6Fil8=Twp5=xDnDrW`H2#$w^(1VXg z&(syYXXArs25T`RYT)V5VGho%3QXy}f}9F!_oBj~e=?gYjEZ(#`-ww%s5S`z6l^4y zkH>1&u&^D+ta9H&HwHD{k`hk+lwpM`6eF)6VBz+r09RpLd)^^R0Hn>?QVBk(pea_e zt-^Ds8?Ta4Iqzj#gI5il?Irn}Jc@VYMZb~l z37PZJLyvsbP785{2sd}%*^Xe%xG+8OI6ACo1yd%l!Qiqizjvglu^CT^kLSILqj_Kw zzJ%7tQ+nS;zO`(E3@J6zseX?PpgU?j^^N4925x{Sbr|nn5JRaI`crE2^`NiiY7Y(H z?(O$IWbPIH?%K0`jxFWW6AuZyC4O-nN{qD_Sr{kgz{j{N59tr=nu}) zK`^6L5I04k|BkTVt~DqpUSwM_co%?ua|;J&L9`?T|{Fr#WqXXm1<&NsYI}iCQ}I7W?Zt zfU5lrriW5+zg!hY=TcW!ieHJJ?v5@f*IkV{lTPPPA-e0iiwz3|(&;Qzt^ue2OS9D8 zzQq~|RS|oMi64Fo=5n}sfb*0eTGY9_1d^U?2=)X(7t1paV zcr63{3LD6)h$fuv#tsU}8F7aR8i+7|@P@;w`iznopS~O8eCHuyq|DnmOIK&-c}@B+ z53{?AvN~p)pIq;!YGmc-GF>C^;07s&>HC&!>l zZP8JhZr`G@$1b7Ar72ZA;tZ{u44&BWCRVLVo*Y}C%Zrm3=Wp9Be|+6nH?Vw`?zY{+ z%BFh|!^wA?92H8pw4MO2*rz5!a$KlXaDJjU`mxh5wOLq9!4ZKF-dg!9Y za)48mf6;AhV)XIug-qTKpB23R09?QGV2t<`x)(ODiQItdK~=ROU~rKdnFbNynJ0;0 zauTqH-T=CdAFyFLOvg<+EIPdPt@K?>#GtyWj%jud%ZrPt0aMvtO8uy*?P zb;rGO4Ui1t!I(HH4JNN*N?Vwr2sqFq;=sM2fxOw1^bm}k1Z|A~oX0m_MHKr7Y=NlJ zdX}q-!9gVqDQDEd`OOJ~pqsuAK1Wp*Qp5q5TBXXfnO!$Zsj$I&oJJrWKFDl@uj|8{-!Xz zMU12b9FpfdAs{@95bi5WuYU+%WIh;%vM(wiJRv8ABF;j-`qriZ3(OX^dXY^gRDmaTKZ?Ka9I?@{9F`r`svYy>8=il3 zh}wBVDA+{>)nGj~y;N)=56|>+qkx0#@CQ}5ym;+!3ltSGlF9hrE6;3b*B)krJo9Ke z!!dNwHU8Lc7Wzvf{BtRBRr6{PS3}pRhX-_rkswicFqE72dK0Mt_tt2Wg|1eQZ)HJn zgEZ9VL~2&ql-cvEZ$4HY-v2R%`tYLuOjsPE=w(&Yn_?V)X#Qa(7M;WGSOy`hGa0HZ zaN6mf=OkRd_;HcTqo9yFIT_b~aCv z*F)?q4ka>vLV3i7h>Gh72V;=gtRFlFo8KF;Av3@}UybeM*A5UMtc*{(X~x^zB+=?v zlvZvJpvfXQdBbl~_+kX-8g^@`x6QeS`Y6E~$A8H8fdn^3`|TrF=4e^J<2OWRAHwvj zu8DB18Nm(EcMo0*jHPa0>QKShvw#u;2B|mz(!wPEaDu9^IpH>OvPSW}`5Eqs*HFF@ z5KBgUKfw1d_`Yjek|sTw59#B*Fs1SRFfZe3e8aE7R`;oY)J>6CjkxOouC(BLpB_J+ z;ztp_ADgI?Wv6woxH_F1mJP4LlUY#U0ZYpr5D5j*%AFMc+t)Y%>`+lw@8cNr>8$s$ z*L;(;8vnmSo{rhJhtB?g9(v5W+vEd_=~2`d^{1|+GYgS;Wp9i`HVAv+0U2*`$)Twn zUbUcNEru)|MfbVqISB4RC1A9xhbi*ha^j8lMR_)L^kk@b8I2#TaQqzwH2bXmbp8;} zgu|Yq)VBRcm=(!|jI__+i0N~Scy&p!I|BB0ORR1Nd{;^mV%rT#zWl<3-wB79FnaC4 z#%vvM2qbC#_Ck3i=ciZXDUglgGx(p(7d>HVVay$yZS|`h@kA)odF3`X0!W}y`=epr zbtKh_JQ@bmj7*n4uuMfE;UgXf2j~M9_Y#Mq)x-8J(VC010p}~+6Om3_?NFrQJ7O<_ zc^uEHlO|)LM5&&T!tRDt*cK(`>%!ERV4&>+M+zkX2oCIsK{Dt$sNDK)c3YYhK@>kC zDhOMgij8p2W#C}{$!2y$K!7uH0yPk=IG4w7z%De9QDP0Szv&#K88-ggQzK4P+QXz4 zn{%67?74`1tv3M4JKb#W^pUtXXEN^sYU!Bgf{<>R6TW1!cA@ztZhYtmU~5C`152HY zR`9>UsBuHA8Sk5yi9r>~Pn~@N=E9R2E}-x_d6^r`E)?`HqYKegPllJup`+Nt_l1-q zPgjm}9=(~%^~>{u- zQP&RdA~yWPO1K^5ID;WwzBvjT_lr*Vk}q4{1N3%LrAtX)p~kCwAnWER$3j3YM`aP1_J8t6N5af7jfiX^gbBr30bylEUu}0F{Ifm z^r{;`8tGU+Kt@%s07n3no<(RgJ)Ufx3%6G$(5=wEWhg6i&U-+jt=>gIyhvxmT?K7x z3BYlk@M>t`muwAjvsE zD55bo4@G=KMRaRvScV*7unvX3uq2LAx|P$J65H)i#DrjuYA+zTVmH`JtWU6)`u4D+ z8s4|S&j#M}fmQv`k*@_nQx|eU`09`#-g+BkMce0Zx~7kPOjJGGL%M870@ct@_W*g^ zs5mgXyte^=X|wL7I{=1gwdQ3QUStE;#!kgIgYQZB?haZT8;3f^q|>PknX76trd|LP zgQs-PNUF@_z|XU)nT*61Lzk>MdpZUu6le9}Isa=tW6s}5iJ70B{(03A+9U)c1p4Xv zBJXf5-rYvq%}X|+@8R0EiCIjGr_^3R^7EVlFtO1Uup052uVe+{;mA%K*-SnWCx8af z^s1mh8vGv9Y@#HRlEv}a?}agg%nP$t;b30YX@HN6gxly@{}V~0Y{XA)nSeR3WSIH^ z{OB~ne-v!7H7j6*Lc0&0!>CB5Z(jhLVo?3a04e4TmMAF&F)#zVT#B$Ipo&=yL8|uMRz+DX!?DGkPPl z6&uYv+o(uS_h0KC>#(~|5t4uBQ0eFRQA!=WuvQ~7QO-|CX|OVHk^cv=j=3aBjXQtqw$FFm!v@w8^-Wv)C}ep(;)qGACviu( z@ER&++H2dk84k4AOBKSQF9P#w?GdOo9?L>gZ{MQ86p94h zXIy@UFNFr;mVedgWU1(cYj#ps0IefW^Uzm0-&sxMswEJ!{bx`O4NuEB#y62m78+yo zGaTvYxqe_}t1M0c>2k)o(7(@pZE?mqSDXv~``i(Wt5EnV=jWx!wQJt$peS-^Q98V4 zTTo5FP!oQ6mGgN=0Up2TT<@kI4uK=#+=UeiMzUGK81S8j&w6}x_}ti}V0e57<1-ka z_H+gFJeST(9dS)^phT_Avuu`w<;LEmh*=fr^@RU!CZbC#|SHcVF8zr_CNZ|y2wO3=4m$ZRLYW0T{%aS${3{J7Vurr_neZ6os)`Hq5CA`!Ie_gwpWd5xPOdASV=^ z#&3zeOMkvdm%fv2=}+nY-_rN(5+04?2D|F4PPQfd*YXX}{<(agcK-igzI5px{y%$) zUH89Dl!*Yr=lhlJPq2yh_#dlTl0?U1e-a%DNA$c1yLu07-kb~r$2aaXY4sVFABFls!uEb?tLOyF@_jH zmx4~@1VWe6xkAb-y9wx6IywXLJ5l3~BMwKL#udMu@XN{eN<9TY#=twNrqVIj=T4D0 zMEPA?6${mrd6&VFSC%O1sV41HoVSOY)HVYfksA#I`*^mkS_u=mqi{OSL10IoPNH+f zNub*lXM<>C%(0mi7rG6Z9UKcNl?X*@1!c)}vy)R>l6|hAjE0%&0a=SFK$A|)w!++p z?cJe35>#UnXRCGSFoqrwUqg-LX;gYLsI(7zwVH(e#pdqR#g zh+e?t1QLj2k`rFZ!EWc0pTK`Gp|2X5AmpydbIfzc#Ei;8oAmZ{F-*5@N{CZFhcQxF z$?}Twmeo=X*iq{6&*VB#l)g?YS$NK~#0Tlbd@7W}M0n6jfAC9n%zfW9mv^(Vi4Vwb zn4{*M)$k5`K2MztcK#c9`=~4ILafB`OftIWQb@DUWp^yakSGy$HRb_%r=!;ZycOsv zj79|tF%*f6Xz1yE08qS!o9HdGVW_!J3N4<0!XrH(KXnKhF|bj8-Q$Yz*mtX~G1suy z{S_h+2qjgBN}a-l*y0#RYrt_Y#2Af9Cje}6E>vO!X}sGQjS~Biro*LVe{x4mZw?9- z0<*AR*#dkPm^^GObO=~zi9ng?UKaWRuw9ioP^RcBX!92uTS2-UO4t$hJ1hK^`JsYy zpnXYs(kt+bD^fu$&Maoo5ebztHUgULJE(1{+9M)>>d%3lE%Of5<13S#Nx4CTX;`_8LHi2k}b z&d;ua^y#oG<%GR)oVODp{#_J|qK^FBBUHt4p8D(Lf|U)m1L8XqI;l%tngBr_%8Ta}<8Xon&^$fW-c5^mzNKKsELAWkR@t1v z$IE%6&I`z>`TSLq*!4(v6+UstqK6qZs#@}8m#~xPM)3ozcA=ie{mH(`>+FI>P;=V+0{XV$)GDYk-gn*rlG3@_X%8@L}L*Q6S(El zYhmB$sA=LKKc_$E(_Ni3MVNu#Ea^5X7H=Va~W9UPWw_m``EGK z8Wgq-DW!dv#1=${)F8#3W5dTcv57&)#W*%g*@W24Xuq1`=%H7jt|<7h^2cVWLq=MD zWhwtwEKK#)644h%~#7-o)8S+;c5fk>ivEgGhM2Ut-^2FIyexfw} zvlf|yF=Ix?&J1mnUBWxb+9sA}a}Jd4q&tI0^@MT_(6$zs^+%fDfM^JzW!TVa8EApl z{GDNH>qltL6g20wi5b>ZtxBE2vr+M}RlW<%dCi&p^dM zfI_%6<3wEl8v2_Fd(&9gcL9_v^FVgNdT=s0u+koLFg^acd~kOWz@<)zO_1Hx_074kya%li3n zK~QjB8Fa9;O^O6MVC;Bhe(zvuPx>Hn)|f5?c7%o-R~AHUcV2#@hlTxI*}VO7iC;Qi^u#V?9~^h%LMh z#1qM$`B25-6nXoRyzmzjeap)!p_uN%Z`5U%dGkppr<>5hD0;ghy$X2 zj^+S7cj~J5L)hp=Mv}E?S?cFIyNBl4&J`s&*)~7l0Y<~Q-s)ZJ{;K|el|SzKzm+E> z)4biteQl^kqPV4rUz${DH2{Fg;&aLafr3vl>j2%uU?Ui9$>t3RlCK3cRYGztN$z0O zOA@~}B_KhKaU4S3Td0^z2zsfG7z{+ttCipga)QMa)MvBt)oOpJtk#wHJ z(Q^_Fu(8_+P1c}e=JTPtAJ!?rMH*71Mlj8_?c{CfzLh?e6lZ{imYK!GNbV3yr*MII zYpVgE|0p%=y;_pm$*7wF?DPskWhgGlAmQ;8h&Q*%b)>1B%7sJEH(B%tUc^=LB4%;^ zgu}@Na9-RcZq?M4hoS|>PGR9x?lqs=5CTT(VYul4AG1rDKLp#Dcm41xHvKJ31_hLB>XUTw@Kb54Al#O}#5R z#yFyUR@&ZZ4rcm6)hTK7lMbd{fkO!``GYl7_kz4HrXn|8Xe!HdXzQR<1|+w>J9OZ( zTGD`F#zwQWmc)zulO4+!C(ln@g743h3lb@HMK0d8(>VVDSBU=aMx40)l_@0+If2!c zcrjO2+QDG{)ihApD`b^WJB=G8$+HTw>0Fd&9a)bTB76RMMlA_J_imAt4k3Ozr$UTZ ze7CTAIydySS}0Ips2TFKTK4=(dM$Y*UK1l{yjgxs*QRqUFVp2upjd*nB*<2(4W)LY z6s!gqGzZZ9g(zPSjLRdP!jtJ-sJ@n1y43L6p728Be!2CfnGcd`F}>Qm>UCF;%BEfy z{UT!4r59sXH6&djpIP$6HX!lS-9?P4A@eHF=+@zh6b+~r$eyRMP10vy2cYgo<5+&R z>6+-o)&Q33p-IHctkOASkUzu*imb#Pi-9i|DCEX--rltem+QvV1h^ND8Bqi*Rdu~o zR|GG?@8UVXk+*?@q2gl$YRUVSKIfL`a?AT*_mpE_YeYaRZD)c-jvX{R*(0HrjIg|n ziEy#{uF!V|%x<=;nGbS-~jLfQ{vUkaxvUml$a}( z=b6gC%FeTu1yZN2Y{vg7d&^cf>MNN}oxC7aA(X#HDh2sW zZlLrknIH_A$@#g=0!q$sn^mx${M0SXnaPdP53>Mx`k4D`2G!bF3i1(Rxngpiu8%Fl zSr?og4K9P8_p|(HvO${t$70IOQ( zftgu@Tw@wc8F^1ApMHLS@&cW&uwXVfP(Mov6Qi0P1UOWK6mE5l`HUeqC#XaVp~?m297*!~>s zi=|+r!Xp-lf!b4|(!jM?qb7DLp392EM2~nlvsAa&PtF*iQ0T8QW@KsGDs8S(=0v}9 zXR9BD&bmd`!rNDsGZF3fwrN5c^Hl>XPhg-ZV?I^1guA>3)RZu>f4r5f2mXZC{G$Qb z^Tn?KOl%@w1|~lW_kID&ex_26AO=a@XrmmB_&$z7mmGj-v`iV8mbgv$@O1=d9lgyC zm%+zET0rltG4)L@)!Aq4+|CSoqgsln5bN-k1U6uJ;tabv*WAs0UDsDHz*J?-4-8qh z!AUYnhTk=L7mehD6X+0xN7%ZlJ}i#XYzP0y<@e&GNsDE>rp)wH&ymqmF0Xvi|G0M%&C_R%;C8DM ze#67*Z*{^Yz{NjKpiLfx<{rGhVA_UQ*=|qMNWQ^_Bm5B^M$LfEZLQ%E0o%64O{_~; zBV3rn`3^^uRde}vV#W3hU!LP!PM&GPl=ZQ)yyix`U~czECMgDWEYue@q@ioG>4f0+ z1~)|SuJGXpTz`<78%?fGeep5#44XNZqXX0NSt`@~nquiTrRdA7&WLSdRC4XazEj`4 zkTE{PfMa=5tc^Qn0*;y-4qe4Aedn#rJ%^<0?6I&hc}JQq-lI;5y!LI)Tl_|Rku0(6V) z?>PBkUHNc+Y%v9qnhdx$t;|ZiERsD6zHfP0a*eKrlv{<5=W?oL`>a!5ysCUgkX;wZ z^&gR)kB27pvLRVz%)rbvS<4g!xV89e2$1{eQ37Kn`;oCi2^L0DmVSO8csJ77koE-_ zkLSi-cC)2g0N&h|igPayGmod@w1v z9+Zc&dhr%^G$f*g!V{Fq^u_(*4C=6>cQJz+jkG-Tav=N4;w>nq3c~6944?A445+KZ zB8`kXEI~XEHyJdIwfznsF(7RZh;yXqE=cEd!}ZH8s`8<#e5 z!T0_{`SbDU2^R;vELTJ-P%hlZC<$|@m4Vl+Pm_QXg{l_gu-wL@Ge9P!{h45rp3d#8Fk~OML%rWzpm7?q={ORUsyIuV z1+W<}UJ{Ldml&_1={cXG zX*98E3~a>~;%<3}-cddaRSWwU!hck4krv7d5Ud?ap%$pe30#$W8f}`OJ$zPK%qP8> zVjT7|VNu4H`7F~az0u#n3L z?5DZahayNqDk==Ay28HMB5Ro5E?adh@vuG{5+?1%mQenU*gNC}j0_AnzEvrGH{o#h zvBW=2Wgtyd=YS294UdS25-(Ep0LSytat4gm4qzqH>W%2<9jIAuqTynUg8xaEk@ih$ zE4d4e5)(SHI(U*2c*#_bT@yRqthL`kM*MLDX(EKr-{eL)?I8YtMDfl6Psv!T@aRo$ zj6Vm(koXmqWH<2b}Uo}HA1(beTxfq1x93N6tqgs+kEUMR{kM;@D^9$ew{pk zALLblMNw46>rh?^(TlhdL+i*}9aI2h%tph0m?>!|DKH>~1!RW&g;E#+Mg;I~9m2jv z+)#F|@ZUw;AaJ1%g|0>1fH!VOe$U?%YfdpC>tYY`(&rr! z5@AyUH(IvPys1*SkidWvA@hCoQUZ##Y+lC2vV8Mq=CdNYflO;0VSdoKcQtLli0C>%)S zRO(SC4F=ZdPm}Jn+3DcwO{76KM?eK{vKl;1&up9;~7 zxlq{-qI@bWU(9LQTH*L&?%n?L%uk-lTbRX8qpShySNFAeOXJzX6A{@=?mY9|XTq2z zTwveqMqk7s4#1iZ5gBz`0?pU4_E^`6MB#%a@I%@`);_s|Rx+U@s&B)j3i=!%3H;@; zJG(=4RUtM_^9xKEzli>t+QtN4hVVLB)h(L=gx>SI(T?vrF|4r-K^ID?zJ2U*hePm* zc~zskMZWBzrub9U_J9MUXewNO8*(rWYXl@gJ`pZtr=8Yr<=t?yN0ML>HPfGM6J z%zB3#l+Xq#8<=1>E2E)px!z4H)tdKZ(s6f!RNO}FEz%;DE+*|{hcC8CZQGX2 zHiXzS>Zvaj8g;@`G65;apf9&6K&gKNSBeP(#AD(1JJ8{-=@wqoas1FW=w@WR_MEgx zt)owxiYIX=|9m#nMzVW+>nBoU*}fJsu3Pw4$N2~CAUTh@LRyB)`voloH67T7H$vN% z08yk3F2I6C$9YL+^ax(b+^yI)?PyU@9Hm)<^F* z((Ek_aUWLhRn_2?12)=Q{yKWdDz%J@$j(G&hd)6^G> zab^_GY;NqWtr7XR)*}nkKD4L4i@v)%T~{6!%jelK{;vy)G*0Dyg*>;+;@MKTVCg2I zfV(I}rEz0rEs%7DwP~FH*fv5sdiR_uFHR_*kQ)|N!V8lsq1`m)#d#e6W|8u2z8ce~ zp`!_s=Qbe3NJ?eAGbAQ}7+y=`EV3tLmsPm2jMJ*Nlh$W}+xBm@Yqn>G^HQL}ZzqqQ z*%VgkPsmab%;j7pdss+a&P{!F3nHk3Y?vD^0Cw=v1a6lidf6jJoqc#66E@a(D47C+ z)RNPd#mO|+v}|WBDaRbGCA{UZ@ElcOsQo}Fsh~N@_*VwBxlr(I==jb=6@kFeQMZyc zHp0o6FBzJXi=vxqu8S8{2U8_`t|Ny@156Svq{c>W?^K@>eaigI5?EzdBY{vY!a%5a zvmC!`V9}=L;>)%&Nw5gY_SD*=C3E>!(qC;6&*Sz)*L9vn>CE05cqE~W5@tn^^Vf9K*HKdK?h*Hqg zi`Br89r~Z@;D6i|^as#g$At2y0Q1^uyaLp`?^betl3I&!7nRIzBeTVeAbfPH?S)_D zhbHHiAbaN)e+OVam?e&Rm~PVCHsHNT3)g~sx;PDU4Ij#9P)(@|?~PGgZf(Y*zX}7a znLM)y39Goll7m)Z$0|TdePV=JV#e9%U8nSD@~VSV1Bbo@&B?_o^P|S zWXlTYr{<@+r)($Y<|XTyup!mVuu;`Abd52W8s?^%$p;o;+G;LGGOb6bUyZ>~S_J?1 zxV8FQ-Lf1vm*L~GgpK^l?@2*EagG<$Rs>_rejM)y|wxraVe>=4XFnZ@Hk@3 zsnF+rE=2OyQ(^4;+)&A3i?IBC&g-rJqVk6wc060?Q9d`Vm2`A}P{9-}EoZ}#+DMSr zwxzJI7DdC5zX8wecVBfc(ltmW=WvU`ME>$uI56;@&K zdTy|E8~IxJWIfoFCx{x@WRmAI>X`Ia@-JJM$~TZa+0jSvzqT>Op9u&%X!q$(#^KX# zr05U3d?Wc8X-;ARDS`;?wl59TrO*D3L$T&46ZE<$b7do2fl+n}8Qg;Rx)w7-8S_5i zcfbuzxIr>I|9aBIF0S}%aSnh>M;D&>w>U?5>0jJ-NXZDvmxE{D z$*45jhz~t3l;_V+4=F56?VAx`=GbPyI|&c|#f=y>C+CPbmpLNNXWSd%g=E;$IQ2zz zI+Z)&s|fE!S4(gXZF#>Ax8lM7Xy;d*!n6(CD5;U`5VmjN-u2r?49}cfjyU=5h1P&s zDB5ZEEg77$Cv_WHEdU*Ond~OH*CTA!bAkBvOOJ3w&zvm)Upwqjv}f%8hcN#>x8jFwr`wB~P8aHmYvdp`Jtu3$F7k#vC(C5JHf-x7Edd)xr?l1xJ9_N zk()bc8%b(@3!{4)Dli)cC`Na4C+0wa-QLd`2LvsI9SqLhMivSSHgWwVZ$%4hH*pIk zX3OcCP2jKnn~}+g29h{5Z;>dPCrCs2h2kLXeZOmj5rxPtTx94rGO?-LLAPhwR?QX5XJJ(PCVP-|_MImN87t){mltTu274IRu!W+p{ zI6O)DlIV$iyYUV4nI_@G?T`UC3#W0H&&q0#LPfr>OJAoE>Anta=_k@x09c~2OL(%K z8|=2|&LUuOEP`5n29$4GNs|z=gBv)Yg`9%L+cj5Sq%5F)4Ub?3Lv+?M<`P3y>!-r9 z9q>et?2(ta7O&s(afL(Cl8ja5TcE0mLafdy%W2%Aig*Kqo?SJEUVF>c*HhlFwG_@FJU8Hj~+M?f`M6Lawtwu`vXo$z3l@Y&~f4GkGSCI69|E% z@6|%&-G5zs>$vMtBzDJ$hruW6b>uT>?vAls#;yR@r9# zLC6SykRcty-H$onVe7gkVV)s5UG5Fi&my4_hoKj$sgj60+(a%~>G3z!&6v9J)tEIx z$S2%*^rZ^)m$ z`u1e-k{06ILmQ=UUwj-YL6yge;%L`8%7+f_=JMZwejAxNARu>>qHbDl9Lh~GsUp}> zSe{TZ&QZ0Hs~vyc*@`=%rm~gPFKvJ2_$?ELLrI;hw(6+82Ix!e(~e)@=?q#z=h9X> zi?W(HNp_RH6f?>Ge>3Sxbv-{4ev~Ta8d+<(D8@r6Jg!}Te4g!vTzpD9{((u@kprsS z0+%M?U=Ek%)k5Mr7)VFGsLaz^V>C_RYz6J7fZV)nr4s%()zW;nC@abgi$M3oDB!Y4r4a_6bhlKc>xZH zmKzN&C3ct2cYqTV6V7ySbp)hE*C^L78CsKNM=r zT2MVE^!Ms-O%3a$VYSATWFQ(u%WG&|T>uGI@Mpk4-z1KBMmzd_om6!T^}EsRY{9yl zo22jC%?#vrv8aSG&(B0!F1-9_B+o)&49!?K%#hmZYvM2Qp+NcmuaQsrH-H8SkX*9}y&dd0x1_pgq~D1tXvKED8ZM#g>w zf05r4>n>atI1iO7^V(zg!@oY39X>VrnwYO#7dsFV8^^-at7?wgcbQ%bd;h=1;0Jqz#-;isD3NO zwaSTG(=2tYYCUM6!%umK0t0mGFh{2YxRKs+OIWrC3`=Jxg)Z!bXJzl{3&(l~K~;W} zybybb;EQCMWyhu`OlCi zoj&q-HJATi64L|gPX3bB{mi7Zb4w%Mi24y-$pJUXG+RIP?b>4th0h8&59eveBN~6h zB;Qe~V6F(?6+q^>N%nQET7S8sZM{c%gswHEAW@?;BBqI&9VFF1tdoS%nRydN*oo9- z=9AZKRxvX|VB1Wmbu{91I-ML`M)EZXr$2$RRl>!BRPPquZFO9!CMh&k#(&9M)-BL6 zZZS-qJp4~3#2oXFY?JU-As7DAe*yfmCECC*zv@~;x5Y?XcInRmIpC^MAa@@dcBnQU znMbRwUzjE#JrIoqIxSQdA`Y#mQ>ZEAUY0#W;tavPh?}ODYaSD`CDUd)8P`7g_ylMq z9B{7j?{mYCziL`M(2jxU3;K2uo*HyQdBPN`su+Y>WF{Msf|K@J39s9z^OQT5@iED{ zWgh~W`Zuyf+?RY44oK8bf*vmr)w+ktgZ(Kat6aEW#Cf>=289nT^tf{gEVRFoHw5`! zPVlEQ=-)s?9L_6C{&V>w(NoZj3@BVmIA3Qo@qpc(667xO zNZ3-s4bn>3}E-qft#k>GKY63Gv-=1)sD{jL)VOq@w>L+4`ZJjoht6Vy8hDnL( zx*uj7+MhU)8FIRMmH)K3{=BLN{xB4vlwF|fo3hvRjxGwL&2_BP{eZ}s4BZd5WXXpO zQ9K)r&UUjHdV7&+qQCTQ2kn84w!C|&G!vT!8@DJoB5tN^CZ~1J% zOrZJDhaBJB*hSiKFKyiyqOkchE=8|W+cDn+*fDGInWLiSb=nNa9;c=tQh zgZg}zf-eI=wTgdAKI?RtOdX%r#ro+2v69lYb!6Q)bkRdu5>y9=Xu2yrs>V)HnFG98 z~NQ+dk)ly+0(SPp*k&3|Aqq_u*r} z-*i>~mm~>4ea;PJp9@bv=lY`bt5k~bl1qj z&THZ+D52_X+Zv@%*T|7>A!$EX#tswu9N_AlAUt96A* zlK~_VwlvzLUK+~Z2ag{FC&h-v-1oV*)zKHV9z<5uXgFD5Gt&m}S&JJLGKX1YX2n{?t9(}YYV)bomG^5^LGFO zaIP9A(o}%TALPPSNNn7F!xRr=i2#X!4eUye;`1j=!fFe}xjL&b^B@=MpJz!;E{<-i z%lU^JDFpj~Yh+KSu=^l4%JUJt7U{i{U>?n%kO4nkmuyd^=b9{^!k6Z!hYR_aY*(h(TKEPSlv05F zUnN!R)s!4M?wli^+W0W@@#d}I-xm2&+h|FQ@!hhYRpLdVYDEAuS$<@V*T zneL}t0SEtbhw%1cE>g14Dij^&`b&Q$CgJ>H&TsL3WIlTZLwFy#oMrqY-LK?#(dM}M z3D8}Q>SQ0F0D5$Nrkf9^m>IFEaD_w6=IQ1}y3EXRylu;i_$175s#yQ1^jy-{}^NSHgtsj8Ue${d$nZh2cj z{q?c`I|Jakt~EcwexU^skJs3NmwJ}z0?1};K@O1B5dGt+!EeWlj{^^17aytqqZhv! zPFckI%tch7rOzXm{3<5oY>1_SHbJ|?p#B|Wi$4BU%*b(}fb?MOwC35F4$a#Xcf`2{ z*AfoNTiKC%SK(wvzMaSQle*~E1fb5u=1^cTdq6ok)EfkjhxK>DYpiHv+#GtZol1dyGlikJYF6y_mexy+hpI#j>`hw z_po2GUhZEhK36PL%vEf6OmQ6LXs35f!30Dpz{#V(_q z1Dze5JzY<`oOXHL;dKX3hpkQ-PTqh1bvxd2qJM{-bh2vcC7-SMyW}&a?{V*Qeb@Nx z==;CFV7K``y?-&@fBjwd`rIqpM^C)Jcm3Y=xa&RdZ@i0{V&-#Zl-DS)Z13~R`G5XJ zDogsT$KTjKBl|dcUG1|^I$Gk@=cMNj&j8OZPm`yeTaEI%$4?%ofFy45FnI{F4Ki1c z68DAfBi%Q8yyLOT!&~{0+xu?sxXpGOEKx{KyImK95(n<~F)2&d>EC4|*1ba~%t{?1 z1~s#QFnv|jmigvVDl9eUXF9jk0Gui*r|;fvM{ExaYx#9Z>cz z`M!JZ0Mv<9`|}3u3Nhx~OnO~1P#2&KJ6Neyhx70Xx+4inV)jRO-;N9z$g^E~S&K{l z72?o+88J9asMLH4FyB5Jd2^f`lP`xN%wE{{JdRoxF5~C| zw%oINR1|C8nKhI5EcD!Y)#Q|4L%7aMjV{ni&hBv8!>aFzNg;N?0oEGU#%5w3bMR3^ z3O|@8wK-96F`43BiwCTUtrZVyE{XB!%+8r`VXwC;^R39T(!Yoek-?;{1%vOu6`rUKqIw|_2>|3jkqkfk@th#tT)2D|K8 z8w;bAt?5&(pPAZ#9~N7Nm8O?EVyP8wueF<7N#VKm&%=+c0)r7}F5RRoqD%)9DmQ6PcT>ua6cZnlzXHZbyLgEU{qMj>aD!}EuF`q0*gbTD^|Qo|`7a6QXzh)y|F z5hFE!m?=XFB($}D5p4Y~NGBkxXI~19JQx?#wl)(u36uA4ua!N&PU8?55%>wlV3W(< zRiKy85fLQyScoVDso8Pk68KuxK`@L0GS77+fnS32e!7d5Kj_7x_?R|kBLWZ5kQ)R5 zoyE=GFD0%@Jcvd`mC>^+bunL?~u2I zO7ldh-NjHRA54bBI1?|86@zR?2XK^uBbDuFFOK%%$lrFf8%Gy$mSi8$KTg6PVEca`Tmq*2z#R zLd!s9@Y&{>&zf{G{<+aHt)sGqp+9n=>>t7#KXO5uvI$L!C7+7H%IGGS=$Iy_7$zsW z$q~t|;Mb^T1D+9`<+C{Tov>ubleeeu=iP^s{+|RAb52*Rs`xX0L#%4IUpygKLc&i7bpDNu#hoVGolIB* zG(QM<0btr)a-#dTZQ4d6TQZ%tfnWzhHEHE)D3;~sY(pTg=G{eh0P^(=>a6zjLqZam z=Na`iNEOtPL}o79Vn|++oE*iOVGR?& zsFEMYvrNGLROgm@$EZ(N>VC!h1?i6uM--XN+_W)FUuPH7vLWk3z6I6;jZs;ALo8Fd zSIEs9Dt!4_HVK3#8@meVvhOfwZa}+w?Xir7R59XRGZPc7olGqdE^_md%rN~uJ9*2Z z%t5svxH<60mMRo=R4(d;$+?8H7ogJ!)7RpWUu_1R6lT=H*m97c(9GKH=TYDt_q~qw zOaOA}Y8|x_EgQ^)eC;!#S!zeG+2SXVtztAZEle4^tApH!Z)uEq)8;U=Gsc{`nT<>e zmz%vZIn^ZONC^^U;j}3?Xz<+2@0zs}MrcQCubEcr*dS#wGw_b6F<{{I4kuG>yCJ;D zgM8weS@}hD@Q23^aaQvBx#8O=|b5=8{HiDeDYzJy(@L6bYZq-@un_yEfW@N zevn1qffZad&>u%)34GQLfimJ zOo@n`5)e#{ESM3qBv$}}RFZ8a?&nqlHd^LFX*s>E4Ky!H!j5(XiE-NLRP?#%Uw_M6 zowzvhBpwc2@6rM=p5!bPp{{n!k9`zOX({4qI_1n=@cON-awfycj#+Q7U`E+1^bCg| zFF0_wI=3QJ0NO2Uu3~6&HgA{N7&I?4tB{)KVfoX?UnRbxm0Uc#3XL)VH?x=iQQEg( z^w052mfA+*%-NN?S-jicT5nkhZLS=R6|%oaI*1vGpr`w+vOBWpi)~e{tlsA9pa#d87-9<7O_gr)_of&c$;W3`VO<2Ij-J#vk z-1$Pttl;_x`4!w0eHP>4vpCiTJ&TX{XBQCCA2=SCxjgt4EN;tYHsX6OKLU`}Ocl~W zqAN=9@V#M6oAB+qr?*S*b@g^>{1*3OM!o9&KN^A0jxPN3-8bi>$CUA`v5f@yeS@CNIOMc<5!Uv^GNkEl z3AG=}pWvtR^7_!1*l|Ik(+-Jw%|^sw%OF3*Oop8B_x|NlteY4Z`JU zBlOxA5-jiaWoSZtMDiu9!d1GhV*j#BU^#a-MkLd=I~85EF^4i1`oapAVr9v0ajeF! zC0s@)&$T~gq8)I3l(xAUAY28y0Q4}*a5Q;%a$Gy(aYHF9kg2}AOV+{6lpr%FX5SO%hOLdI5cqw}pTcQ?5(!V` z$H*r_$DIOiadg*mC zubTo(sbc=Ny2Yb0B>_hywuL(=@L+0-5PdI(5g3HvfC`b@3o0A0{=Q*|I3k z&3G6|An*XFs+drMw>_H_?InqF4t_CrYMzTgQlKzYFW*| zc=M99C6rC`m$t-9w8BScx!5oXAl4##iN-h49d(*y9{AR=IhZ|ofvjU_LL0VHTc=r} z^DOlCWicNXC>Havm0(-Oq%M&rheC4`p0*Dtg)!#DO}hZ ztNnK>7yK>CY1?#^E=}S`zy!w<>JzDNKXDLKy6pE8%KYu(Sgi$_$mNhL91K+W(^!?oBbPD5 zJS*9drNBukI`e_8M*|MB%DU`<_H+vj9}L=Yol z4QMqGQ54$-QA@>Y7(C+8I<&pT+5sGH1L{|Y*4k=Km>f!bF9J4jl3*?aA^-nG`ds5u$DeiID3ZWdn- z%?SOp(&UvhP55##YGoMB{zyIj9bwJ??yyPl&GY&NtClzJGlhV*pRf_Fp@3JkoLEnn zTLI(6WhJ~NnH{gC1_|x(iqPm&*wWXNQc{&nOY!q{8W2&&f}hm_e%2I(J%?rFq9+HU z-bDr^%kUdFCc$L9CYp3}pk`bYfA_yA-VfnNAHlct+SAz1kM~0S`#Hwo-6jPvD2*-x zyYHd6LjACFrS;Tp7#5e<5ACFuxRjD>fWzCMQckj8DQQJxITYZK+4`*4Z1c)#Pdv|F zcia@;e99~5qv(2M_tFE>G2;B?fCe-=Su^i_9%P<4r_KnCZ?I$n_Z?38tWhAE-Gsje zFf<#>zJ>X74Pb(gIs2iBMvqST$EPUdQr6Cz;IyZHcoxRG(E`Ry<$@)X_R~xNQ;|;H zeAE-%Lbi~U1?y;3ol4c4<zop=@E7~` z8oWY_wnW}ZjuuDgCe$uibZ22qt6Yx6Yk6Lz{POlCS&=EW=49ieca~8yHjI2YySv$# zs^w5ux=!2F3+h5W zxC2ax9OZ3)PxZp6m;{FhErgtElHI*T5AFm`W!-oMd8OT~t@6pOhT~S&cEs6|CuXAk z^d3BKnf&P~t2lrAYGdo*m!S`EZwS$-Z~Qqj!~bA^byCmEZ9k^8t`0V<#*_Lqzb#oF z{2_3P%J-kF+awuXhTtW3wS6BFvlRL{Ahf(?UP)>?h>5G;$Mlb~9g&GRD3Qm;l4*xNP@Lwi7b?K zg_4Eun;tjFyhKuCdtX=D{K`?NO5e{Y!&nGTI{?bHpfOdEliR#3U!`Y@2W@qVKL80_ z21ySWw9YpY1CO*ClBhJtgV{VTu${qoUERN#mM`jnkU^5cTvABC~?1+1n-9TfVTS!K>=od z;(E5C85g%%ypF(6hqbEV-T6UdRu1BA;Tv|PlLADF&plX{KO;ElcH>GDie-i0UrZP0 znt$X!P4~8W_wlHkqnIUz8a_*a?UIncG^Tckc6;RE*0(L5IWz6td=jU>fGWYsV$c&@ zK!~Il^)m}xrYA~~U4j3Elqk=FRH#l)Htt~CYC>#oh;f#FcxTTisA_X0*DN4m%XLYU z!*i;C78O8tRF=!2Tm@9j{B}d9%W!Ye01%GLKssqx(3mA;M#QK1u=j&B>RvkeBJ109>rP-D*tT1tb6<8AjmW7)? zF|T?okD^fKcr;e=3e!Lvk9w25zFS|ie3xZJoQ*UL3)xF5*h|H6Dd}%2QZvw%iTC*r;^ibqwb|=Yr}JvFQz`Aafb*zBj%X9&NP0@FAyM~-`C-}mpCm} z^;J}*)7Bm^-Hy}NlC1~YwQ`MQNwuLZD@;43f!ntbeP0F(ScT^^h9+!}jA*M!L)kx_ zP@2F0C`Q!CxDpE$i9MV)9NuxahLVjgfk4LgQ;^tlTArOSXRTd+QbmATe>>XjC= zX&Nd$XgCh2ODvqE9!^^FJPY*k*9I(zN3D!XTF_j}8QEMFd!gRo-*~W+C`7_AA9h+bkUtdN&p>95`qKQHh$2ZHz`qsV? ztIg5EkgYm+1Ak?lvp*o7pfTKtM@Zr-UV}N~;ak83n4?hyQ8bmo^R3qjK1fPYieIJs zh^d`LEuM0vFi+(XR8SkP%@W7FFj#m+;c*FN81?<45Ji`!hZbdOc;vSgju}$}ZO`n544cTyYNWwMsPBz@7&8*-nP*`_CXh01NmQ@OyA!g5m-pawFcVYyo{)g^Rr zqCIk#+#Dv521ex{Q$=5k{=q~ z2D(*%*-er$3)&)N0Uu)3uOUM!%<=&Vy9|0(=!ga~spQSd{yJPGvdd)JX9`H@V3QnJ zqJu4h%=Xs}vS3+l6HLuyaR!WU9>s0??C~mCKrx)wl@67+xd&*N+>d|;C+n!z6s&~l zbwXGFCO3k&?ON}WYaf-5L@GvkEmoBx=c5(Hp7^FJLbpNYEiQkbT2)4^@<5BWr_b$i zZ>)RxR5Jq<;4;rzL8o+4N6n=3%-yqJCD8@T>{E=sin>2T<9^i;v9q`i7N%C%F35 z26_wjL}<9EdG!M{EP5aA%^TzZhyz?UG)*?VLo77w>|r}`>#{0fFz}EWT@R#@m*BVS z>SoflBWyaj;S{rc!L>-KM8N`MvM!6@i3;Wi@bW{T0zQ82u3ox=r>AFm@!=lCFVnY+ z>@_Gp|Gk5|*tS|~E=2|r?DbQU@zM6#obL3a*4gp~!asRAN&;ACol=b?e9qFl#pZ!U z1*kQla^#@o{2_*Cm6%RLOn;ApG$o>35Kl>;qds_DN>>1fFWxt#~Gdl>N zIF}(JgN#;a-gaz#=<2KPe9MlMg^?)j!ZLP4aloSGWa$Tq(v(-NFr!lp8Lk&S3?3(X zu_8N(j-w^Mcgmu5+%q!UIcb1&F-MJN+bs2~>;16qQ=( z;7{xa$zrgmU@G?PQTs@HXv}u8QZx>rBStOWvt?`oI-P^IEXUf#%a&vzc1vb^XZ<|W zoJ3SGK^-r7zjqP_nGp1h8M15azJnS=ODY%qqCI7g>*8iKjrSj&;8Lu& zn4s^%hj5v}-6D1M-_oWaV0{sWicvDECAYNE)qCHixE}AV|JFb>&&W3qlG>+?Uq^ys zMM{t~4(nNtql*bO)}mS%#DrU(M-DqdXoo?|%xNMeiP;_M8MmC?I9^yQ9EozxIc@gylXLmb^-`QX_2ZQ-1~q>%v9dQ#Dw?!!l_Y z&n@BoFS=n!g_U|+4^$!aBdTpja*otBGTYIVLU8{?3elj0?-eYsgSTfA7cADt!h}H8 zMU=cd(X5cgBAxmw``kf(A(^ctrAW979iQ5WfoB23sNvcG3i0S-`>I!(h^jK$Qa=Fb zmYVbr(mS*XgvI{|w4F2Kw7KzJtf2Y>0Q@xO6c}?Q=~tgj<-eE8Z5lUFFRJOH zyd>pUrfx4u?`O9}k&Yi_`ygpo`t(P4R`xTNKqUTNso5q&rDLpV2EfSj4fsogY^5nA zfe?g&{Q20k5_1h+!-2j(V!q1};LHUcUGN;dXkONjYE;iW;~E3YQe9p9Z>}sS+ga(A zL)VfexUQ5cdRgmh5Vv@m1tK|v3zFIFX>trc5*=PS^Gxv7qwL>Jc1jvp>+B!yYFf;V zoM>OUs~;v6Fqg@_>iS^?)Cl?T{Y|vLyUWkC8M%Bi!K*-MeK-DC>tEw9ia~smgNy%h zz>m%GsDYLu&w*ibGp(P=tDqp#z0O~dnH&0H$v3uj*3Ac z7l5c;h{J*bRWi&n20anP1F^YrSu~`#nrsqsGi@9gzw)GY+NPB}C zctte&_XEwG%(gO_)58Z=oA`GSm;VhacZ-snBPxb`hJ7K6lKIe-NLG(FFF>0Y93GJ3 z;0_#aUeMECxow3d2s~EQwGp-nsb1DChX66wgO$$7ZdJI3P>-1lJLn>cI(D(RgUcRU zOHYiMl=SQFFFt%_H$s8ME;bY9q03?=TNO6&laUj-`-WRY%ly=tk2I1w>1X^ZrHeg( za5>4cG8<}vCh;C-*xdDySL6q5Sos6Kk<0KurO=RrE9nHuj-b(d0mn#DlIq?6A*(zO z(&$$O(mW`ZkbOe%Pdt$EUCar;TVK?oOp%kviq4l%Yvs2%-wcPpBe0rjOyf z_dsNG0r1}%cxNJQGXUgW0KKK_=u1`f)FBC^UC?vu0O7pVBjY_mi!&tm7vu_UPe*~c zJ`?SsJLf6BN{Fu2C!E*nP5Dc+B5NLv*a?2L+BWm*v0!J*->2D{kO23pVdcKOgipcw zNYA0H?_yt8(Qlb8JcT$^#d-}C(J;#|h`hKArmwunq}G`!q<^4?pz0oSJCGjh7TNOc z`Y}-YjT!uCcv4F^{T0M(oWwat9;iwbEjo|*xIE#C_@>TRFrUS{cw3mi@FaMlPl{#6 zlkk+?S^UPJlh6jf6^$Is7b!gCB-Y)Nh|eM9{W+6Xfa7FYqUj`vGM}=Z#3&yLSIQAx z8d4d%*c5a)y|S@zCZx#iCVFi?S-xBH)3>2h0+{C=R+bEij>EU9l=MlK?}4g=cYKxe#sjnWyFj$wRSf?JWY;vPUo_vehATX7v0q`PFhSK4^U3u#V(UU2tFRmoDZbgfq)@&@ae?QOeZBAL4l{9XKL2c)ALv?e`Yf~ zx>z*;HhN9pNq~||Wy&|Zxm~2TZ0_EU&iUk_ayJQK>KdH{TzE7el}7AOOo5�QTpV zqp%$Vg6d?wpyKiXKlDi`)D*rZ+AAlJ*KCW)767P>l1<5!C5%ZxU8aF^=6-~T$6r|= zi5=ucdtC{_h!E4XG1y-)bAcAnn|>TEluX^iZBf{I!yt>WEli>S0x&Nm)v>s4udVCF zO|xh@i?Z$PS$kivq?p3-SuQ(zM8fFRJQRQrM*7ss0{Or?Ik}w?Oefgh&_rfG%9N(ljOkg9*5`E1*K#6HpCNpGLX@bmCB7oLG9F65^^L)R^Ik)Dy6AxN_`_?b0lvoP3vbtx8SfKG_ zoOV}X#YXQKWtSXF`B2BAlJs{Je9NyJux=pIo43U!?MdKtzd%oJ8!%cpufC#&kw2d| z%xU61JOr5eL;0bqAei|*m7)GspJMjKA{!kZzcaxz;mitwIM$F+EJhPVXNu7ore zeZM4OWnB2;199Pr6Bm$U=IONY30aXI*Br=mifnr-4Y4yXtckvsm?OQ!y?eZJrb2Hi z>jt-2yhZ3@-_($VS^@KrU^p7_^fK{C29IX*54`8*flKldxsfvXIOmw=CCWe(LaxcT z5(X!F<`9U6lxPGDlUjbw0&-zh7yG2<0|Z~RN$ZPCmm%BlDD>zQ$gm^${-bb$#%F++ei*OHgo z%jj)W$Yi$J7FbxT5#(us;0*?Jvak%s#U{v5e({4>`B2(bHaA=z%(uoP?6#ln74@uM zx#|&W>yp#R%PJExz6V?pD|{{vUS28=O8VB+7ggykGHQn#`aUL`v2^%KbYL$fOMth1 zXW{gV7h+^rYYM3wytXzkU9mJ2;e;y}ArWs;7aIU1@UinT5UyyVY*{Hc;zj$?QqtACSOVY!!X>v$u{;i|V5 zasY~g(u$VQ&Ferh`}IPQ=gsP5*K5Zl4Ah4%3lLnYpr|H7tpdc)zz*^Z=m=8!JXTN)C*$nMT?y~&{*-sA#$i-fH3p}egMG24c+ zZvDz-RMH9(Qq<~J#38^4`a<=i1$zqb5UhxaVj)P8-X+2a0WZ^=G^eB!rP+ZrPYLL) zW2ZYi*+=lwmbs>bG#p%LG=Vd8>LKaWuP_}_Fdc5d ztXHiNOmp2>*0<2Cs-<>H7_G*qHW!YQALV5x@7kG757t}|H5nH~pE7Dv+iC#GMkShi z)m?E(v&|(k+g5LLS6%WdJS#3k#QOVXN5MpL6tqLh>6gI&4W^K|l=z3MsiZ)E{7JO>!AYs2C7|p`@*NIxoGznBwHORMsfy_dc+dII8%;~pd zs4iGYYPi`xzL=Jb%i;;-Z1UjA4VA(V%OF<5DE_QhcDq*BvKq^Y(VOpUQ}nqk9^pJ| zz5NIHe--=reXdvWluot*g4Fzpql2RIBGbigz9UwU)U$#YPsPHNT zztOVe`^F}Gx9_okHJ$v~8ESvr)IgZyK>iADcQF>&wjLQ&dcuIpryMX{cK_tz;Sx>3 z9V|C@Fij6u0rhxDZ@rA(B1v9EpShFd{U^|m?_g|BMIL#Ca2|s!Ahl(+C(1uATYm!9 zLFW1ck_Po}_1rVdvoOC0GJ@|frITra6ws)54O<$BH{4(SkAbMFIj;^pjYTbDK0gN5 zgPSicY9KaHjl!a)Cjb+yj`iE4wbqaZgkXC0?4>2IXYU{NMUm@Rb%~SxQ!)c`;D_HH z8EMN((`{&{!^^=Sgb`lqKzTmF^(re$d5EP~AeP9vzQ2_A zgK$0|$)Y{^EZBHNtWqW)l3#%qC0B!SVPWMnZpN0d@ zP}a#tRl`Zc)dox#=I;E7)k?Xl6YOjDAZkJrj35mKBH&eM&?Dr1l`IckZG?!}nL>VR zGe=yY0ftr_$=7DGMO&GU;+R(UXRb0^C`$kpySspR(mrsN!> zcy3gi8+Us(h{~@hISPUf*yak0-WI7sY1Qmt#QtV+pob4f7U6&{Uub@!v)J?#Q+Jg> z445Nr^HP>3ytJDngFcmr#-2t}xmS*NZXLqRX;k>+z{{bZGjKuk-IWMT)z`6O?H}yp zo}FMnQ+iVj3l9-|q&11s5xFcLBr>g{kF-Dx$^DsCIy>3h2Om3T#=wo~LW*Pd1_k&E z8gqV_Fe>h-IH5@DkOir1d^0+zfeV05$)AJCcMjE#_h53De3m9o){&k=@3ROq!YePq@jSg*>2XC0Rzg&m-b0c; z5w`DBzXCAC*-oeBVhoYUzaO%7AU{#|9AF*9P$gn-MBCE!MU>)DAV-3O+b;Mx7p}J+ z`W7;ap`;htWkKubCp>6W4DVv^ALPe4*&6^yXeJy;_R6K_B71f16EKC-cd~b@dTd^3ex@6+3XlS~xio zSDDgaQkYv*DpIrur&6#ug<%f+f(*ZBNsxJX7b+WYP|q>FQb!hsPr^$2emjyx%C`fwUZcdt4B% zGR@f#SGCT}1ysh-!0L#rTBXZ(tXiE=433h3$v>EugYAaXOC09z<+YnkkFI4$e$Xse zSz7O{KWX~2(E?V4X1t(Wio?l}iT)Dr}hF94js-|aFb zUbGJ`j#cae^b-u|=keh5Dc*JO_Bu*xyO5+yB*b!6lAi% zV-01ef%JDW2CLR6fh76ZND)`*_}j@=Rh~!HL>d7K!84~fn(${=V3cPeMGElx|B6=( z3x@9!98WlIH=G$dVH1qbe>ko4FM_e(V`LpS>Vp=}>u_tm#Yo>|Nv+)*ULO$&hNL5) zKivUVGMTMBS<@kZblWI2$vg}ld|QL@nT%hB!A<^NVYOQ&PT`MQIPR=i)^ND>ljIu@ zMs4zx6#J5NcqBHtx>6x6>3u5gt9@+mDvY+mP@&6}vDSWXC%HJDI5MD~QE#}U{N;+9 zqNm&H=q~np1@BMW>tF3;XDiMlX&At`S^b|K7u^LZSN2=fzoM`RWT4w8ce3&d9lGlW z#{yKbzJP3@PS#mPOE{u~D?JOzJGR)wP`rdtnOhZCRD6Kk<}QzW)4N07CXZTxn^hgm zi#*htl~(5$1zmuXSG7z;yogKxFjE}n`n1Q98=Wkvf*RDxJ^?Blx(`EOve#CK%E`wb zs3w!q4CoFP10i;utf9t5Rc^G!ug`{hLDJyO^;DDRJWJ{#i{w2U7iAG>AoXNqC}g&$ zEdP;w(FYT#lf6?-A;P>(TyM2JfXIoJI&kg7(4BD@*>Mm*Ywa6$xf(VC9r`Wm=pr|6 z_-||sz%AcOid&nAaMX)Z^kPKYGaEF8o?DfqJv|#?GeYf89kT|7%2S8(!(9Sdi}SiF z+!5I11&WI<^m|ywCIC%@fqY|jxIg!a{g0iU?4?SS1RolKF-s0MlH{Eb%x~3T#%k!q zTPUt~rz#kWOT6jY5){JenLH;uB+okPY)tOAL7F8|H3#Fu1p9(I_JQbRo2tMq&gVc; z9?yr}dpxi9nWT}WH6z+>~hYu07??3QP9|OP&`+(g^6oeMSB`WaNzO zsGm0w895}|%Q*jQ2+@p1Ov(L_^V&0vhtkG@#347;t;L`B$~nhAmMC?3+w<$e)6I<# zRt(a`rLYx$K8~g3Z9kcz+og#UEm&G5{|Plgg}6>~)?rEN`y~WsL&SN!)g#be0Cr0_ zCilAv z&rY_vdKZewNC9CDzYHKc=LC~aEfOr^1`A)mgi?A?=R6xeiRQDpEwXII7wyc~3DwnT z0SVnou;={DlpT-EcWKS%JN~$PL9+2+D;n~}*L8W35v{3d{Lpmqb)=nku{$-?Gu+5< z`>nk++a2sitxkydACgDgud_ECj~&n&xa=M593-eKR)G*$@}y32aQ-}?aRsmN{}LXG z7s`2^)@J6BKyt7Y=?UKICYj8;rQ3jLN!|XtV-uP-25&mA?PA~7KzSk<8^}9d>O33M zc@ef|MGN2OMV7xOqVq40s8Rn4l51ITlwCa)j+=EW<|dU&Kwt+JX$y zCjrZEBZc%g2AeX+0bcShw!S zu1KGG_fXWKK4$=yC!`)Q9Uk!CY%FWv-+|gt7hUTuv#*Qn7gd!~l76zc+`cZ#BdP=) zWvJ!ILelZN^Nq1hYL7|w*(LA6jC;>T2j<1wUf2N3kdLIieA{Qg`xelujWHr&S`x^C zE`2QZ3FvSzH(V215w2O>=$jL1#;GTPFVp1s)#6)l5f}KCZl;`MANZd)b5qo65TN8< z_wO6N`a5l*Y~K?&>&He;dOe>s{te3Z#>;Np{VF9F`JIw`xlYMh@Huy0$+hC+S+C@F z?Nf3!7nPhD<=i+Zf4ccVZfBGMD_G%^SvR16#>}SXm8z_nO?TFvMXhWQ6!DS`ES_i} z5qjf+4-bV&zp;svZEE7>wEygbVR|SedT+l4u=E}uaf7ys8_Qf5?4(%T@aBTi{|!qM>!+9t~FqyH_2OKytsK!^tK|v){q4SCiTLKzM)CA;pe}4M4z4K$~(u1O>_Z^5IADZD*vdew0ABiLi;OUWFGSf|U@?N(kq} zXeuC7WC?OS1)Z(6%i(XKS_r2ZlbT|*{XI!~6f;Yz{tjK$@`t8llKtzQmOs?#)cLc2 z*LutlkY0}qalCgnWol;si(8!gFK*4Ze@t0S$D8e+@ANDfU{jGAfj~XPE~S$-Ouu9{ zUiMh(QCt&D3)_pSuHK8O*5NLv8x4OA8&>wTU zSM#e)O4->5JT*LU8IYK|gwg}1rGj}eUhUo_DaoNXKbAOh!n)i@1B=A7&z1nfpY zU~mxXV&Ep^G#(CBo0r3LLW#pmzaaV~Ta4gcv;D!ID`q?$Y39h_6dg?wRj!zHYf<9EeCW@6QR7dh8;@Bxm;cn&H-SHJ6rG9A-FMCM8? z#YI5JC3}|)uaDB`q@S5rH{Ny0QG94?Vj3=}&z!ubS?=}vRaJ{YRsPUuo>NCTAQt~6 zi7`S`;yhDy^gPqx#INH0<1vg&&au_vH}k=JF2tCHJMrh(a-_$^&F6wb>PDl^_FSQD zz-(L7gD(VbWO3d1ez*be*X$;nj)+Yu(no&wfsQY)J=M&)-A{CH_Toniaw0e?$*0_& zpug4Kz*CdZK||j~L(%+sb;PHT3_sk*)wI`LNBjS1G%tadIH!o8KtH)rkjz8}8XR5c zSBPM9C=bpKegb5q6nX60??Ti5tiK3}8CNt?lJ#0lry&P@3+n^}vfz#s1({U)&aq>i z$i*;R14b|pPEl8UP(i|DbNde9rz~@gYsKada(dE!!$3d(hz*w1CC=7tnIgpfMlII_ z*WK_%jR5i**iyW=aeCjv7(v+e3trg>)A&+6{ky?&=cIB^L3*LMj_qityx#~A82D|a zW(dX9kT>CZjaJB-6+ZJ5E)1w+=FRQ?iSrYL;bE+DAnc40 zyz_oy7aiOvpW3g4WN36+Bc;jvWP>6|=3oyG&U|zwjvM+Lt7#{n*2h2vo7rxWBD_g* zlHmEo-dgM~qzGdg(pP(ax~75)7}AmI?4Nm7oTbCkLi~3=dTp~zHMLo;#z~tvP?nAr z`vHJ_!#dWE`b9US1u|vBckO@SpfAc_6ZM+Y&_REoq2n`*My=CwC8Jad`Q21&CI7~k7}&eFsxOF@OXtabcC+tf&ehu5Pill#yee@bJX$+n*|$ zHz|F#`E9Ynj=G!tsyL!SzjWo~LpH+(a-gU}&GrpDLlWXp7nz$6v2f@j$kT4%Z#PS+ z$c%QdD&Uw`*s~p)tv5weu!{_Xz@a>N zgRQP~1tD<5xnUGJLQNg`9VP1a2f(py?Zv4rcvF95OG@g04OV z_INff=W?nU!=3D@%4URJlS$wwG4v2lk6>S**jeSIVo)?9VQr*Z7yuU3gOlAlpQ(nK z<9nv$=m#?(32xF@Oo6|2 z&U{plg)R>g3dC6rw8Pdw}o<<>`bG;~aHKg5p9Z@hvK!nO8i zir>NOnpjRV$MrxzbkgIKCUH%SHQpMa6QuRi%lW8qw-1E%wsKxygd%W5aNd$~@0_`y zuS{?r+TY1G)o2QWkw*$n+2O>OLsJ8_PJucssnCF``le_frZf*H=|MZzU`HGfqH}Cx zmy=ztaw%GGmrn=N$U7Y=?e%P-WTs7nu`@z?G|u+o`Xl>;(CeigZll)Nt4lT8Zi+jG zkpUi>K)A{sHmlu%2+n?sv+iebU2F$>aN{uIGIfCO9;D-LPl|p0MfB&! zq1e|?>}x0Geb2!QA6lLP^W9l-i4ExhrgU(OAi!=qWSPJ8M6*)9LwqVjzldC0uP5p9 z3nRJKjqAy(`f3TeEC5>BEck87cxf_cTfP3yr#^*+k+qNfOMT4S$OW-x(CsC$qFy?1 zWy(P~W*=vu8EpX+(Un2YsQF9PElL&5}7Pz z;WCuD(%T(uVeL&ZHt^$UCtFdY{tvHV2g|5+5E&(CDDxLjwf5;oDC9|2-IX*sML1+z zx}IETUzBkEVJJq70+u9Gst%ea?2Ah{%dSg2b5v}b)rUc0n+CO&flt;VEUR#UwfH`3 z6dk6{#Qeqno&mk)ewg>+^$!8LdTBqTH@>sIyk$|JHTH7J1%w)7Ag=T&$dfpq003z; zJU)uP&c12aY!l}@SlU4;J3~sdrAQ%!G51_Uj`fMd4CrQR#MJ)6%q1v6#oKx(Td;;C z!tH1*n~I_CIaE2E8t`%SZPp19f2)>=f8@=4zgI-hB?gGPAx?U(`{H5>n1ttiUZQta zJsa2la2g?dA4m7Kt(RoV8oOdo%ad(ud$x7JQ!4X+$mW}YZE!(r?5(AVCWFw=H18v2 zuy?)+=0sS-kIiZ@25ihw)SiO|k!a%deG{kQrUK$BjJCBKxaTkL0ty?{i?lw8m(B=FjG$>%1h5qL$JdbZ`2{_td*v1eOGY4wwB<9fEOFRkd=rm;DD9(HYMFw)K&RPd?1Xi>Ci-4!hX z>Iti<2B<&Un%4d?y#K@qi6Aj8V?SUb7;R}AWY5o>+zbx-dT^oBGoh-=IJsIE3=_TS zkCgy3Ebb2Z#(*#7GLWl80Tnb;u1r4_*$<@!9$94(D51CzRA%NozQ}XA5 zSMx_xKU?<@zP^s#>ZHpXKuTE8p1}Z=!+Cs3r zL#&0OEEc@ywcVV495_i7%c`KAaJF0PXWCOfL`|e&^>DDzbvQGYAY3YrXmuPcyN0B9 ztRx(0N&06yC3lmEpwlB#|L+8EEFwq%cd$=uUxicN!L}Y;WC|AE0zf+*g^T|OI2+|B zs0<^76G-QfFDXD6AJ<|w$`o~^{|-zni0r7>C-#eTuxY@go$PRR7}60=U=cBvy*TaP z6Y(~C!%5nalZ~!eVk(J4BP=Le4*kO;tBwgMN-Ad3ifXJU8- zg7eO@8&b`(@pj)m1}sEIj|*&q_>DNIY)rhO`Gj198qG1X#s!L&7-Y*2i+f-?B91Du zu2ZN-&QU?TE7!ef_t@!`YZ<;RB}xn$m>1a&&m3{smFp0uUG58)+HEI!xB-#3`v53E z*-lAOw4ipdl?Q#07b;B^ixSI;^?RjySmZi>Me;b{^1$MIMtBN4+wpNru4fwV;2q?`>FabN+C6L=y zVZx9|TD=o>GbN`?2lF{d!tw`5drGA`SyHq3Yf~pn!I>AC2CI7~ORLGj|A%X+M6kz` zrFkBf=5Q>{wDSGLJ~T_liG$gy|9^)q?BMlO?wQ)|VCSnzVq2upo=$-CFl5HB!P-_+ zsfRw(Sw;W%m%d-Y&~y#TI(DKf3Qo!K@SnJbB6r+NQx~(hGw>bg-9eNT~}9Q0d}HcT&eGt{-bY-zt2@5Qz za2gE=-<{+4L<`(-Wy4VIBrWCDOtMpTjSz^SSDc}y4Z*GTO4vcMk|opte(Op0?qU?* zG?YhA3Kr`5XI{PTv(38zWQ%c{ZBc`Zqj>`bEBRz}ES5F@sN9|IW8?Yp^*+eEoPz&V zZg154V9xV1B%tUT^0!|?WaFE4)?sS3&b+9b_ZNyUqTtb#+?%2$C{~z}&u#uVIt1og zxI-vD52tuGD7Pa3SDaz?cJHl*xbGXm+M$JL4frVf7jRFcHUgmFymL>mr#i6T^i3oD z{O`tMIS&i^82s7XyH{9$$MQxWyCr%sf>DBSmtZKKS6DBz zzv7@v3QVumC-g0(?xhgF!i2jEzg`$?id*Dhe>q6533xoiuJytHFT4&eDKb7NsmG_7 z#3?>%C(^UQw}cmOW?X5RFbqI17pPBA_#mE7E?QROK%AVa8nRgB$n1Hj*NQpu^j#w`@72>(%A9F*eBUyOgP788$xuM-`cLl8(*TiCJ=B%~1 zl(?GyM~?()svzJ0+T^Mh1)5fqWOHk4 zDZ@6>7ZUi z&CEx8SN`;!vU==&N=~6@2+4ZH{k*ABYzo>!X1vkogWD;$tc^o0z z)YZXM6)&}3(%ohOc*1V>&kB->BVYyEog?uQ9@Tmm_A4lMDEVgvl|#`+MwQZ`4xOtd zhn16Es1Qoy5#UCh9wbc3oSG?Q#$-;*v}$^*dzsI(zD~V47KYlajM4btR0e?|MGWwI z*ijm8%R}}Qbf{5>XrQdM&)(%-U^4lemj4zfsZZxwe`qe$6_+TfrHt3-MW@3#2yKOH zPRN=e5!BXyEoybuL$C1ZzB(c`Dt`0cBz=JMF4$%eCKDv2dNCG#4 zvwe`#I*r~kNi_nTymD`|744dWKc+4--A?={`l4tqHV}vIZC2WType9-!Op>XP4DA% zEEUF#-=-1q6KQ3)*=y~$8k1PqpX3DQcS3Wr^UK@VHy8?G!16XBD#3wwrOSV8_`Wr$ zoB84Cjb-k5@)<>^QNXAJ8o;)H)uuby_DYywW>kpnV9P5=BU#l!8p&Dag#ZN;d`R73 z&+ZPP$UASXPYwlkQtaJXHVZ={wn7DgW-2FV0mf`+vZN$T-tA;=2OsM$5f~!3Q5=c` z?}ojGurA3N7S$7-!LPF)EJkQoO$8~#IzZxei~&rd01o7^R=c<`-NR~! z2+vr%*h|%y#5xdyeF&Nvs^m;6%`cKMPs4F~9q4AD@=vlSmkvzi{d1-SuT|pLno?f> zju8BQ2fJUR+3GGFL+6_*$iaa3d#If3K)Td@mg%6e``TUdOE}rxO7c>;zF))lFbg7X z^1=~48lypNMwoz;>>D89-BlfIZjGk!2txYY1sblzGe%=4vmB5!P!#pSgpV(YIXc8X z8}I-e?q)u8mwgC2yrU>3KoaIBc1C&*!tBft0u<2YYE+EWD37~fne!i?O)tmw+;8@v zRlQ4tQ1s!Fcu_N5P$U*jc|1AIc8;J($Y-PNEGX8g-^})fd+Qs?i*Fvc>puHXvIeQl z+!RQX{uLVC8Fmt4p0hP3MaL=Qs+Rm1SH7_Hw<&mU-&Vt4f!;aKMs@H3bdyqXjK7l= z){vaNTFv$R3wwp?u`9W?v)#CiN+tIc?10g5ivJ}~$*J)98QX5>D$U#ud>L8`%(nvt!Q@8 zhd=JQHTFY$fwEd|f7;D9SHk17(>w1ho8nA{dj5W8Bos1#kP@^>ooBSQTli7N)?Y1@ zuQ|>7PG5C@3^0o@F6RNeD3U$8K$IxtL6vGKBi<<88`CoatM}l-8dN6= z2t)3@hJVPm;BAq}f541A4Jp|ZMP3EV2%ulnP~_t&oJ&VgCwSCN!KxUH*r>8v=#u^; zg@>#Oz57yQ)M7I)Brnkd3Gam`b6s*k&n1)T*8joFuI{tn5ox}>)*ZOgmKt){cd?}v zz!1y^i=VJdt3APfcl3Uky)IVx6>)Lr*#@-s1-RW@bFoQU^hgFxvIp&X2cs}k0{#>pP6Wl zyDAz(Z{0zAsT;SoSjkyc{nex7$JjFK^ZnIr`QKkBazRv$4y4+DtN4JOysSIe!lDpMa z04S8#5wCfEmv!q?YQOO(SVl*nDIB(U_h^|_vzN=}tuzC@Y{w)vwO8xhAvFGB`B`k> zP#OwVI+SR|SynGvTX7dY);eH-Iz%?S+d6H4I#Qd&RyEauH``xGVk_{?8&*#eThe6R zF+e>&;uss~_^v$~f~)t93ZY>!IL_4%79a9G=^OMsbv*6Mo!oj&Z@P>J^mU+AXn9A`CM)}T-I#qDS7<`7T^8PKeXy|yy7%lf?_RxY9GIPc21-iM0GBWk;laLw^(Dx zKmYJkd-14z!a2Seq#pL>E%x^gV{3$lBC&44yQ>hk{dQTZ;&BVbQCd(2QDe~QE>4>b z>{5H^<7hz14GS=wxQ3rua(l;nzLpt4AIzl)ox*=Kitmt#-XSTB4nmkBdAh)nb zR{y8f;rQ}5>pM@YU*a!VOP^K;BD~2_Dc0SZEnJ5`!bujGeg(n_DzJa) zll|ZRkNrEb|E;^GX*#$gHHO*1EPrO(u%=SektwPMbAy2L) z$KHSbc2iu24)_&O6tjg+sqOQDxj*dgcyH%#T{NL-F|*VAXYiQ6fGy>k*lirsQ(IQNBh0aoPBI;q%qkO3o)$$qmA191fs*T*?2bB;N;qbp$Uf}~gSCH#{p<(> z25^-{OH__V+YXCQUax(ezF(YZI?4*2K>VcIu2l(Fl|Nhx6O_59*<}>X_Qz^*9AVZF zA$&gA{HKG>U!8NDZO0ZFKOJoT^s4~B@o1%3^Ze*F!=nH~jLE zep&F#9js-lUem$mPgeq*nU^_vIvD+dHhI+6tC~Mmd(0MSSEAEe=dXTw;#F2CP8NeX zE~u@3F7{l-P*9>i60cu4Yy)QGbm$_tp$8R3S_HHGwY@%hgtff3m$se~t#1aX13<8G z3C`kKhm^t@tQTQI;DOt0k2sp>N+5wO?2q4{ZJg4ooJA9@0SWC2VML=kM=?xfg~)oN zuJjYsSy$M|Znwr9VXz=?bVn(ktb6>hx<+@bHJ*SI26cO)R?wgq+&Be3Z+@agSsgE4 zo{(Cm=p*F$o;USR9J{aBbb^g{SUvS>t@#9MAD8dzJ5?vh^FE4}9!tpB=QVAFAS=;f zx`3bUi*6Q!YP423bbH^6fX-@3#j$=T(|X&K(*iSkS=*X3Lk}# ztuY4bf}x0_zt5lyG*w8E*Xy9ccC%g9{6O_Hvg1zcsX+B$?G{Hq%N~t(drP{_Mc5g`Q z)dLha*sstchpPjE1|;#r-18L=J62@fmvhPZ5Ut&5gd`HP=vb_zF9lIOL=>~`)DdWH;UO><4@#2Dj z)SZS)gmewgcHQD0M{9C&D(@ehFw<`F&P6d8PXnKJI6i9O_O%EaO;{0 zTpvfw?2;E+|2jfF%y?nZJm{;w{#<}E{{s8Y8G?Csf&IN}GPX>Y?p)#=gzr((_phDw zSHN#vC*uMe*kwI40`qvh{{=R#>zT$N%w(F!+OFXkmE(nZv=SFxXK%tcX}0_A^~7L# z0nV}GP;GSweDc>+48j@i(%g4;sv9Y2-e_2`#693PjgW;Lt`dTd93wjJ$#XuyQ&KDE zA~$IVU(_hi`3(2%=zM!0c(`po{yDWa-ottmX9?I zA4|S9Z=`y#{5XrYR*h8aM_pyxLAJi&{pLnDxTF4Tbi*Y=rAt^lTN@YRlpIWezu@m@ z>#V(k)fWCUYkIKSH@qL}syXV7g6gyJMOrs4cH(a4G9y}xyM^A|drK z=!fKK+(^zAiX%au%?`nl_*MO7(NjYOt!WM9g}8VnmW-Y4WR~7w@jw+e*Q@jWO#IlG zF}os-Z7*3DkAmamyCh|9wm8E!-*nCt0^V9}vOAFZ(t4CmE_2PFuaam+aYz><-z67( zr1l307_OK5^@ax8LW+OhWJ~K+#EYpkv4Xlqqdv-p1FZNHi&rl{THLN8d5o^6hOoYh zK%Ti+h%+5B-HYZ%UKifzo-@P$6ua7$Bt0!v5eF8M=AMH?HK&k&m5WR*f@x?fl8*y) zHb{*fWq1RGY(v3?!*O)1N^=GY0`7Tn@u@;)k7C+;uk53h1>$kz?zU z5__4rks&vFTdk?jsGpS|We2U_J)?fX{Ltc&@1A=Ka~(ag{}_6M5H9zm>*55BQkq`J zQ3C1)rr834Yv?Cj1^JYt{whLekduicQ&I++dYQ5!jkbv?>Xu87~k`8CmW$9O?$#v984d_g~P^Zmnsz?)HhsPY~%GbF)c zwrlpbHD=)1ueq5YUfFZ(-bGZ&Q^I|4oUIX6Qa`G}@Ij+yl0AM8=qz*PX`?YJuCNa} z3~^jT4v>}!c#RzxFPz2=jSPL7V#ii>d?AMX_io;o+8VzexBB{?3h6*DO+RdpTfvUR z0FyGC$N2r+>ie8J)V#3X9S1D2Ws5@%@3{ZiX7uTmZEP8z>|SsOymCgHHf0!Su#7gJ zl<(Sy;odWDxE1*BJq0AxCj%ilsxd;8P%gZKpk8GI9YNK0EUnt)L@IPy5+h{J)s7=c zb(|f5=>At-uiROJHqSR-wi%@xv$?5QojuF0gEFiEo)de2*BB$gGq^*hJ9+nQL2*x6 z;Ff#a#5MQ|9@6|gjsGXv*X@~S;&q2b?db3C#tY&-D+n(K^;^4lCd~OjZsutQAJXjablkgkqbTr{CJBgTh!VpTRz^TEa32Wc3gm|=%3dN z>OdZYYqM28S{-h_J2gP)4J!7ltVw*e(KDa(@0F)Dc?cGhG1>x~Yc8JcLfsnEK;ME! zRn9;tQK#7Fotpe)VPJ(i*8|~E{x=5t_sLU{H`(J9Gk3lsd<=|@E0f{6*I9aJ-@IgD z{=R|!s+?17+5fe7?bE<7VbsCJMPO;~oHn$*|7i)qYP8%<@AyaS$5g z0W0UTPV&Ror^5cUpr4B*E>(_jl@Nn{8Ri@A?WHf zE9ig?*K1y5Fvi?dxqb4kfSXT=h}nIOeW9w36jn;s*l~7ViW?X9j%e&vFlL`l=#zVd zowIHVRWDWF0_qgl#rZc_yF=A4$&awb)|q4AMnBGCyUNg_7`$|<>e;J6)-uY?H(!~n z&6BzzTmHp$cFeKHlr#D0H6`S1_1&3MW3cwlgy2T@RJTlrIwe&QD@KDbZ7P@fQ8ck% z@9n0^M*Cu`CYbtUN8ICrYae~MH*!YbY;LG$cHe@v(S5U{XWSDYlT)iEV&TW!p$c(O zC5FY*i4&?+IRkS0qR1e(Amd?%W%^8^^CjSIDBywB6j^7 zdna)E!Hs@+I@hyJmY&U4`4qMQftH>(T-tW8(t9cmyDKcTyYTK%ELhj`u-@U*w8*OD zDgh9_fxodIU{TznuhDG_1ST1KfcmBb)5Pw#Su2iY27tWJ<(9v zH)Nkt*k@AZ9b)d8|>r**>f z>S3eKb+1U6;jbDKBkYO{M->@f*>ZjKx+Fv)cZa?X!7|7~>HTBM&a;Yc>))PN&sSVW zIEU4abNifU3lPp8WAG^8Lr;q_))8T9z2YicCR%5OsRK+`*;}Gf(7^svimOZ{fz^A% zp)^ksav){1I(oN6t0&{R|JtDWqVE?k?wf@bcBJrh{&AKMd-jbw{krKDRSDO4w~N=r zf{=j~`QlTMc`w(+3bPSTswu%x&A7?@MeEftDEt@LIthd|)agwr@c}5uAdC0=oFDB6 zLhKmB8-wHvJoBlM17A=NoT};c$a`a7-~3oXmKh<;5r7zh2|%8u$^VndIzbnSj7Tze zAHmq|n|lfn-ERnN`=Y*|WZIG;lq7stc14V~nqN={^KsUa7u3%Uc`XS(RIp1K+y07g zng-NaY0=1j#Uhjwsi=R)+WrFi=Ng;QY1NHa`$UVbGb{e77oMBD)9fG<4 zRl5<-c#3Je$4WO$7CbWUHvYDl?0erNkE|Uiwmw2w5)dP75l58;?&YlK*!7M-k$d0A z>Xi|L(en3pQtnUJ$KbfYyh@O0JAs`4h~MYgwN9d>Hz3sY>bAWt6UBa!4>QLwD|Iqa< za8Xq4|1-M_?7#vmH@PayBBGE2qN0)_;Dky^TD@vzm{<#HUMnxIp_h+?XU&~rC@Gv*jWPuU~~JoJ4YzL$Hkq?l;#ibv?>J$cUs@N z>@w=^zMUgX0Vckmx&5o1WpLyUTD%C4eX&y;2mA*G%2zgb@Lr?ZKi#<+JnhHQ)<*?{ zdHv3F=+Xb}JOpCRj6fqa-n&3=Py(4%xC#&5)e#QsS9ANDJKq7rpcaS1q~IyB5Y$NU znrzcl)03$aQ`gD9%^7d58Ixr3SfkDEk!h1}e3# z&O!dbiK$)#-|SyC)r6BbiFmgleu=*;LF*ahvm!ktuj`Rt*D_J`1)!W|1G}WXBO!b` zH**A1aR!-u3J8>*T#Za8^U}m+i0POXqnGNTpk4vUuV)sUPuWm|z7!%hJnh}(XNWAN zGuawr@Gtc#1KQa{@dVByIr$jW8=;)rts>4R;haG5wN5>lIbE?4%k2&{WHEKuq#2`x zM?B8WtVf8EVakiXwn-JEglIlhIyFj|U-#PGzvT@UVcmt>v&#^x8q|WzNFK zVwvcZ<>!K_?Ecl{f4h3>->xzqzB0?{4`0e@|8|x7Z&yjdp>f5@hnig5RzjPT9*O{7 zaUUlWf`GA7)ZMEf0i%;FkF6B&%UMPt3>XdWS%mxv$q&k>Asr_7DZA>@E1$bPa)qZ- zTS^-(cx7Q2J7Eh0_~$(9?(`&L5-n}J*V3Mq{^bS(-PaXs+H@*!_*q`*bgZ0In95@K z<r^*PLtFx&e0OTA3XW+RQ zzsk85L8Tg`TJLG#0aGB<(Xr?b9Z;lP_oCFDEQI)$$0BqAvg3>wue?fNM229GNCQ)Z zexss0d!c4b-H$2PaKq{R)VYCG7!EEOrgv2CRgNoUO}a9ZhIIJ~q5OQ6-VjozEB3P~t2r>)2s>u1bf*7U87{;&8(@e}3>;mfw+u=qPuaN@TAX zBO=;uLKI)l@{$7AL1426Y^OVfmileST?CLZw})>JE(LrmD|Jl=zRm#Gvd&+|>tKt# z3{)jo*u?gB+L^xQ##qjnCb~WfsRmbAFKg`{emA>`R$8)n3*HDc1um^pMXKOGjkA207mf|xr!eWyb9n-WCj*-F=v{q9zWEvS**9 z8v`+zt~dlTrnAffjZnnAFI({3Q2%_r5SAVrdzDPdNKF)pA7Wtjyxp9_2p9>p5sPO;p3~2n~idO`ZxF*q`=3twLpp6eJzFp)1bD zoHVg2yRLFn4$AVYZ+KSHemoeS+4e!k9h}4$hVM`nUS^L%|1lhjo|oQ*>pXNbsW=)} zLa|d$pOY#b7$XeyI^5L{+n-+<_EL$LY%q$FY-5D5gtKgG*NmHPzey*D-WQkHx{*;s@NV@vMk8b^#ghsCtH@sS?PBy)m+GBBizu%jhOz$QC z*0j#lKW80iocY_fnF6bCv`$3usUI89%F)g9$H+}~Hgg{cOyKl>X7nx6Hn~Mt96)SR z+_Sh|Zu{$|7h=4gM8zk8BRG6V8k8PMb#U9<$Ax

    I?0xY+utodImUaU%WUHJm2KK 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 diff --git a/TMessagesProj/libs/armeabi/libtmessages.so b/TMessagesProj/libs/armeabi/libtmessages.so index 3397e351faf491d085a1b0c7c7f367bb1ce8b41a..2dfb8c4e7bd75ba8d1af3448161b75d7bcb0f4d4 100755 GIT binary patch delta 276236 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 delta 269827 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 `ZA9I6-dqyu?5B05h#(eXq<+ya3mPR(F^=N=v0( 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 diff --git a/TMessagesProj/libs/x86/libtmessages.so b/TMessagesProj/libs/x86/libtmessages.so index 4ec139a3b619c6b25ead730ec80907fca27165c2..37c61f185c136f5a62d9e894269ff77fdec52c76 100755 GIT binary patch delta 393801 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±D`_O7Qt5^gC4avHAHO!i)C_1)Yt6ceN{-jWOb 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ⅈ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%0D`>FL5yOH{uv#32_Rsj5wF@ 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 BhFJgr delta 389879 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

    gc7%37YklYRi- z_>*!<)AI0tm^jUO$54a7-;^+kpAyPllekq8yOhbZZz)aV8N-_+J5^@+_7D7k$y-m& z?uX95;Ger?=C_C1jAngjQq?Q{DtYrg#g!a^`X8AklO**a}* zqmP7d)2wkh=A!rhtOhe3T&pGN1ZF@^fd7uH6BUDhF=Mw4ky#U+?(iVKwg+@Xu)kcQ zvyra&q-fXkZAPml%TkYs;YSw|gI_Q>C%T0i(ZDbK%p2&$%oKy-H^3l-c7PDTiSw}8 zSuLH_^k}Viq{=A!%I9GjB8`Z$nzdPd${I&q@20u?)xWNE=(~sg@DGNalkAgDr>5Q=2YTk9J zUD?SvGd=o)&tA~U=!YrHjD0p3WL-DLbBbm!mK-3V#aMQBZXxm8d^IsCxsXjc#(!82G zqz3vQyoQKCw$|iCIAv5xi0-xj@*qM%`P>tpG&W1OX=flJi$KMQP}r+NP|` zArdCl$n3ynU<=Hqun9q(w>lgB!&BX_J~>jmo^{B^LayYCtfs{1OfC{7@r-HBqv;ei zOm&}1eKRqG_`9xDSF^9IFNUXX!h!X=si9Gi^VSChOuG>0f%dRVB`Ulf^`JnF&%8$A zfl%i7muGk%E0;s;9_bB;6sae%y0uvDXeTmfWLl_W^d;$`Z_X?lgYQkpos}bR?NbYl zO`8p)tZ!VJu8mTk92}lXc#vzeEn;eqtNi3Tisl^4$z^vCSEFuEIE6Y>260a;8=a4#O&YPbH|`8;`=n7Y zLLGlKpDwlKOz5Njc>vd$9pz3 zylGGFVk|5vK!P^2&kZHdFESU`zz40LFlz-CC&wxg!kzWAYM7I$J&m)~=%!gS9dec3D-D18xh4dGP7z#?IjuTx!%-KnT%IUc*B}88}7kc=oC{CsYqsK zHXi7&BQnTcEX1QF-HaL1z^WIdrd``rC$Rpa5;7FMn4-KV07lkv7$n8`H?y5ta)^Bx z#4^4%P}(aZb>PNOuPFJK&Bg0^G^)O=}jNx2v1E5Lw- z$Y;(=67r(O=%%ufKB#TKlt51!!JP$&AxGtz6v#Ne-wA`Ock6AJ8sy?KNsON2E33r0 z)I3^Q>D8^r7V4yQ37JAy-yx%Bu}^2=nz36>VrZH#3L{{UqC1jUJUe9p->g_) zbD-cmbI}w^TW9VI!}UVns;KKC=XcV(5+#Um5_;DipK4RM#0`PO?93yvH1WT{q6I?| zPc8ulNS})qo-RlgAnz;eU(jA*k$C#?@}GW@#-4T*b|ufI(5pmUATbdu5hUy{n1Ka5 z&@x7X!SVm$UUckFYIr_ZHGz3)Sy@}p_z>#!I7d8B`pR50j{OazM+%snqDIBOh=#wK zN(9>X;un)w#5yQ*8u;xC3kY5J-Bdij^b6TLfjWi*Q+$?*Im6JjobIGON;P-3jK00o z|Nhh?kF3|7FYP3jyecr+5h|f3jWaxBHY09Ee!+fbMI}!3j`F=Uf>6X>| zN;9x{)QdbTeME70m2j)*oAN3#HEUN;b+VEri@d;m@IS^-p<{frujm3!9PBrQJNf7a znJ_NQ*d#IKQh>D~rW5%?K$aCFa&Bc+l5=H$?PrV+e=wOhRf?4mEGc$@2xZN+ejzJn z5luheV zFx#?r+`p$viK3k<=>>+dPGCV1dc>EBkty5CzS4AGNaHJDM-VK+R4YVOmreYoF#bb7 zY-d8y=42<%LziaNRg-Iat7s$u(f+gpU4%E9=|VryK?D&97u#ewgL`XttQmW$3k?&o z-$7)IaT3U{L-bf7V~4U8y)4@r6G)T}vBqR@A~M)Edx*KHVIr-v?S8wt@M11UO+@uL z;{u-jUAZa5O*l(R-49^hKOtXgFZGUG%#LqO$uoEgu zp>dswzAXxym~5UM3UMnd;saD~5mp7K1g6^Vsid3fiNPWP`y~FO-yc)enDMa)HOe<1 zJC)hh^YX-7x(-PhDbW?lU7p|ARlJTc#hIJAwsLUqYshY^ye4tcso|&;fjAqD1 z1Zb$#wTf0ImaONiQIlqw$-Gl}tHpB+m3R&JmF5(gv2N$_7)OOHD1>V-T2XXs^(hIM zBKEmCMyD*%`YlXdGjo$Ob0NQQiUxanjxo4Ly;VFSai(=GzGQH62@a@*_MFE=cy*(4`pU9pkJ*H7o4!VgD&SFmp#TJT#cVC=o zzWI9qez)6y;eTDevo4QBB#}6=`6u#$klp#;Q>62JhyTrZO@8XBeAro45;kLHkV{=l z(;MFOwJrzHUrbridi=bL#+{?Shhk`*+Lq#gEERTD*V!#A1#`v4$Z3f(2m2K^=v7*{ zSwN6}lY!1qF%uFiBMKj7Z-WnkAw%S4SysUqk`rf|3qN8o=Av!WRo) zY||{w+-qj0?KQiVWw?i4r)yGwTU9Jk(!`MrX2S`sxc2_*B(qaplzE(Xs&QgCc3Nvg zcSGC5ImBszm!FcFvRBbHA6&sNORYv1|>7wMi*lj|BV4> z)}PtdHHU3o@lIO4y;*|1rTgA=z4n?16CJHJEa+i_MwxqA8FZ-N#Iy)%OQHx9S>3-i zz?aE~RD?uf;EVIL!`=|Tog$tJnBmEG=GlaZohIU@T9)JFE1_=kzCqXoD=fZsPS-?a z1UG`F7yMBXrdU#n&dEreilLA&B+Qj&Y&Oh_(x(W!PRx@phVB?Oq%O-Xgl}m^GHTco zGj}ntQOQM8Mp%ttIT76qp>SR#jEgRI24beJ=*puj(jk+W zhU+uDIyKSxVmGTf>{%FI#sK6AD}u|QalMjLR4lwzS(zxxXD%`mbCv9mkj88!qbfXJ z@68H04@~spZ9vpPjE|nQp`@u9h6t>C(j35ne=E;o5*1`&lGtUKQmN*>cVSF!$!{+X)*F^|x>{%*=ALQw_CJMvqZwZ^`wD1RD6e zn~u!zky!-d$hk1KHDYK})S^ih468UPku2mdsf7%295Pv_B9F*+x0Z?7g24<fyo(Cy=Z2ll8JGTKPPKgOPEDw#=po0l4hpqo%BU{xsDYe|GX{mO(KGBw zSM-F)Y-qG@Bm<40E+7lxbF#*fHC*sptN&=2}A1FBt){K92rZ|vAD4z%ilv2Wf^VGHG#cxmoEFds2 zJN-t<(*Rx|Pf4T^?qqA*C~m~#Y%UHE;yf#(;7xPE!Tpk_xPbU2Y$(Y|e#-Tsr1=|)k9BW-F4maa&mS@8%dH7>Ju56W^E4{cGXB@ z!2jHMj*=J~LuZR&rZR(lPO+B}m?$`agU1RQ>w3DkS3)_^%qp|w?Je9{+v6KWwvhur zYn)}bsl}!DcSXl#``xEE9_fbt!ARrm@CTz+JB0rB1o;z{*#(tZkO`bM-fo&3{`Q}h z43kQPjsDk#*>(*UHks?{I6?t!)?9aEj~Ow?zoT}c@!Y8FyiBC_aKE%+0m zr=BfFvWW*QMDpKDa0_TU2~NZ(LFqMl|M?{kg!ui@=>yJ}SMxQnal5Akcg?rZ#EFo6~yrhaq-xXxB5|Q z!x9L;S4f3(|CgFbeI$K@EQtfpx-MHol!Y}qM>P|l$S5EciZ7zM@oj)`C`ZQoW*;ve zioUAo!_t%=8WSG`=+V(-+%JnJzE!gA$S#-`7;sC#|`t2snc{ z*Pwb~?Y6LU+?gerC)9IJGVmb0Txt@8Im*0nwn}y%Z|V$%2umPT#S2^x-Kg@^*GkQ@ zNE^y}OSG1_NW6Mk$+D>Hw_yScCvfpo(;e38_V zlUz_FcYD-bZgRnNx%)!h1(OSw$lbf@E-$%Yz1%gayZq#WopQHc-3>`D$nbObn7SL5 zTp%aLICpaww#r5%7gWpbB5vn4N4P9l6^zg!GkY8Xb%n_r;QQSW=U5H`m1M~iX~|)m ztoSMn&F7 z%VtLS%?f!(yguP&&dulB>8Bav$J9b$8=ds%MxS$E7fpgGS;+`VGj*PlsZ@Ft@V8p0 zNEsDVnNQ96yL#!yF}>EMgBF9*n3VhsxtzH%8pZOSDtS4HeSUGGIXDH z2n1MS*PU+U!m)2Z-8i|!LK4O#vN$p6bmCgA{GfBoF*;)b6Jd8*qYXf=l z19ju!wWHQ(a4a~L78#xN58_(u6E{p>o>~8<*Ya)S59!uV(a$@m9k?Eaf9G3W6+5dK zhwkjz0&Cq_;nZWY|4Wb2-${%7hv7!wUNwS1e4+E>OyVvXb!OVN!;OB`TQA_auY4(R zglFmX>e-f`#!91E!QgcsQ4q;MS$2NJKbKtgG5;sdljwBu2S$IDfRTFpiUQ-b@JjKB zKz5ydOO>im@bZ=Y6;9M7W2$&lJPx#EC!ztC$V|##GMW=s2F6Ue<7I}jA2Ih&Tq<+T z6Kn=w_fYdKA7PW`5$>>4us6d$YE``uZVU?XcPXcbP_$ML)GiES6|2S{_%ikTEMmE1 zJs2p{K0U=T_&v(UHS8;>DYb5w5CjB@{u!**e&6lXX_S}9k01e>0s05j>}2Q zU~dW2jT*0|1Lln#Bt8MV$i8AU#{do^0k{Qa*wRkNtK$~X%n~&-|5bv?NC~3>6$7Cp zowiaEJls<=v$sjVrIj=fJ_S4boRcl9Sz}hf)CL{(4Hc3-j z2|H09Fbs3uWO8t{Rnk0>UPS~pa%j{#cmHOYSTimwV8Hg3KzsPfq8DQP9w)g1QB*?s zTVfQ#AjOr$p)id~D#vM&Ayd3O7?DcW`U)>JV*?;9=7R4rwHIDs#x4>SXhty98R}=o zw!!fQ2aZQQjQ%PSP}O`WqJVNJhE4+lp+rd-gppmaFN+m(lw`|A|+|!}G znnOkp1ysaJm;%6aw0;arff1ffu=;AfyE*hA}uV#j0IV71UGsg z5TY(bkS7v7zd}mH8wFsR@6x0^lO3G64rXUr!-6cmihxtr+Jo1h`OhBE?!J;Hv3>N$ zIj)!5!>LjrG#m6MWp4;&M90q=MNI4d3JUJ z(v+PPE-p-&e<~vmv*Il3_U{(Aos^0xl*ED5&Ur2aFlv=0QI@ClfwG`7ma3#`2Y9!N zy5cQJj!>f>B0&o>9nt^NT(_!tW*AW-=sWja_*9Q2m*y^R(4Ow_Iegv zq1z-1*TP_gCX&m8Ntuq~loo<0FT_@@tmr{ye=S3q`{=3GPbkX-WPm7AC~;o4WdxIz zh9sW*nH+M`(WbKYqA?elvGxO~TsI~DJS2m?NiR5F0&{)pIC|z)EB13R6|&hvQ{P(g z8?GP_o^fVMA9YxW)DHeNl+y|OV3+2Ljqz_{O*(46wohOpE5abGWVT#c(S+ca9 zY^H-iyQi$?rRaa)w0;?QIXSFJ6fC!!yp!j@$_ZsTzFgc%b%PiTHG@U9?P;p1Xp-N3 zP9j!;gB>k0^1_Bhxp4j#^-FR{5$V$`_-eNaN`hIztuvf+GysiABoN8EYMxKoPL@-nPsJvp%4ezBG z+Urk%qr2Vn-Un^VGLw^X!p^};`U5xwM%069mJ0QCZ8TbjBvOn!^$^XA9_p#%;6_r% zV2O(rA{!!g0={sjNlXNM!V_Vu^>8n#0pdDKp0?+rLM~wPL>inr+DL{!6hTl(j`qnW zwJ78zk&%JohDErQ#Q=v2FbORa)TZI1^E@2M@gS8+S{#z?BCR9VShT3jWHLl{Kd^y- zCql2tG&x8bm%S!arBi{R^xDbqbp()*uP5G7V47~o;XPbCzbVk>EnQK+z@bPxnvAodw|^3pPmMO0C{VVJ6~*f zRSIU)JxOH6xYWc=;#-Pe`bQXq1VOXWVCw$&oh7%^s~N%R`#(@k=v{f!noF_$x4#!#^?*FJ~JoA&eL-fS||yY8gYDi+9%`Np8IhP>o0&1e2q z96CegSOHZ@YXrIqK>z+hzGSnJfOey3+O=wI2T};>blyS#9Wsq{r;U{Db`f&4_)aH^ z?-agRnx>qmH}cr+82(h!j3nwa$uJ_6T3Fx~>3x0HtnTJoy%9C~x!JH#?>tzenLIC~ zG+{5mzjnm9zBr2%(qRo?{K7x5oAG2H2iOsIatdXE1=&|*t<91pjn+OhL!3pcf)Q1G z6aRZ8HL0Bz^kq8_S^ZKW1=Y_RyLypY(@2h!wlqa%NBscGY4uacOO|~Q%ZI^Nl8s)I zT_=1yX}s{`Hj|I;C9juZDpzgLJ9AxeHrt)e*pnlv44xZxd?J-_tKA1HqJfPr>8~bs^?{)pCq}4B7w=(4lFUr{Un%F*zj9srV zTE@Btz^tSltTR^Czf++*=kSG?nJ_Sxu^;^kGoAyP*jFm1|99m|IRReMq@x-?jnyXBcmFec%j0O+xdy~b_?BCJ&U4J${%y-*Sg$6~Y8UH(X7-+@ojde6d0m0C4 z4%zpEwb;@QPn-Kii?8D*wbG_pMBc3PByeH?)H^BEkuxGE=eP}z(0So$xY_mUzd@c< zv2avc)Xwu{4v4L%UD_mu<4Cjyy!?ce)L0beGZy|>Sddyvj;IFCNa09uNONt+$gdL{ zW|VZxOneXWos7-`tQA)^{^2gL^Nq)ALJ)JDcU%Ej)vN2UKXY6RQ_Fs%|GjeFXUWBotNwI`$nPVP_)atLBBETI>X@uFOcy z{`b-!69bj^5%$;_64EE}sl{1g^6g&A~;{>M{PDJHZ#;v%iJRN#aNr2ekcs zFQZ3ToX*IL@{n2r&i2zhzw?--5Xm$Cr9jo1+r|G7jA>3^&?`c`ojRVI5DMJ21i5+M z)(+8TZR-}%Y=~7DOlS|gqVH-~7KbzTxlfVvY{{*_cto3U@7;TJTlRxT-!G8+HtYUI z?wiuQqz`}L2BGNZQPhh9pO#QQXtyu@7X%b4<@REe0ti38L^vJZNO+yoZ5~H-bv#VH z;+_*kvfnC0T{5Uod<;ImWCdm(Ryf9i5jpNp59m6nGR?j0M>-|KOR=O%6^%i521|2l zg5JxeN!oY+{x#(Yzw-Ra#Lnw&nrT)f>9=$7Q|)T>RG=P z$SdG9$-_?jCx}`06?H2vk&JE^L3@S{2DVVw_LAXGCSBm>Uaf_9A-$e}nG8fkBUkPr z`@9OoE%!_WB-B>212&wjvjf5#S4rDvY6IaO=cB{QzNQq?_zy}2t?R@VYL>z@S<_nE z^A4<)ZmZ1{YZZ`?E;TWDj1+CjX7uD``{k)#%oRiC`x!7N1MR>>}Ly-#I zal0vibPT@L+l?0)$DGL&4CSlzb2Hsho4oqLm{+AZe{L2pIlQeUlpFa2#3W>DqrUy} z#YV4i4KDimU(rtbe4$a6ibp!_8Ko}LB$*k=;%4nhPVDV`@2IEfkdF>TQYp%o$*O&|6#q)-xaa?5azQlfuO-07fbJ z_3o=c<0_O04UB<2Pev=ejRNjimYIUNnht>oEQu8jL{d)h4VUpm4`SBkME$Z!R#l}D z8ebKg+upek2x^O)U_oeeSTw1w3Go$)dWt-g#s4aA26FC6%@oJe3U39f5nf0cypk0o zM^84RIrO$+^kg@S-{a}h@nTxzSNN!VHvs^$h&P=CamOY*g_@`h0A6oqq5&d^~m1yN7mv`|3f_R!xSTx)w0 zLkHTW=Na8IM5gLNI!yc0^NfBc%U$BH`RQ7UPbp|;LYP%urcQ$Cx;#*)W$kiObW~)!FGOUXli~K8fDtzv+OXBzTZxnz*vvGB z?3czHeSAyokH#Cr2OPlWK)*$npx^P!5X_T$E278y?fgn(z@W8Ktc&&xDiCD~G~&53gFS|}0#L=E{h3>b2+aA9BA(cn zO@x5wijcr)qnk5YCP<;(6Cu&vGV7`m|)Z-2pzNw<}6 z)H6svz?^E3Ua(w)bOOc}piuLFg7lL+(BAdx}1ZUSTXLtCh=__#e zr2McwXv;a4K9X4KwoRl)b>D-AI)?XTBbr-sSemcN{Tq+r#uuwv$OkhiPf+_^A(BU< zb|a4%_wzrdXmIFy_g*x9-SNm@{fvJ?W?iSDKagavx*INMb6rVUC41vy&)J8o36WgS zfs(>VFGuW59da4@YkFGf79v>Ik>C((5T~C_5mW+}dfZ%g z1_G4B*86is%p7-zoR*oa%rn;&PMS9AubJ0x!X7luDx4&ZNT=M9Fefv-wzyrgKEpkq z8$khBwqZ2R-ct$G*4oN* z(EpTy-^!G8cWQ_3Ae+0MQhUN=qu24s{BL(jA*UI?=Q}zQQ?a*RZrj{kd*NhbkiR6? zer_^LO41xMV@e=e$XQyjy{3Yn%;>xQK{pRszP#zTmh~I(-ZweVv zbi=wX)4GZ1^wHv>xODMRqjNsPt14JUTf(hVsUgFow5Dw?+>iQfE`A7cP@2Do-zDys z@@$=UMTz6>I~)ddN}P3)l~VR9)MaC^YxEWTY9?RjEv&F4x+#yWSl|5z#y!bfJTs|i zRI#35WeF>WwPq1tk_>7Uz;Kr#^5fl9j#1}A0@6~;>ms4{g2q>8l8#B!C46@hm?P`* z8ge9J%--TR*P=Q)drmkKVbAnhm__@HZ#?H=cg zJqQ&!pQQwz>-kQ;@TgcDY)<$r1hO6-jsWtlZ)sD@sl)}fCLVMb0btF6PNX*WgpmwM zOE}I$K^dbSA-cEn1q_&b#8Of#Len*DsV&Du+{+!3i*&t~fr~3bNKk(sjH)FEYu%5d zM$~;LihYE)Bg5qxH>5X|XQ1c)i3xMRxszcy&Po4J5l*pe_V>7b=*+Ywt%B$Qr$8Na zX~uHo?e7Z#n9!J)OUEV86OTe^CAnGZg-<+XaD-gxxjy%mHyANgVsd6fWrbTyBVKiw zKOE;fp9G8%-wnfZpP)WZmDeM1?s`Ud=5}7=TyYc9B2JdFN-)z4Yl(F`fw6ii!gOjb zFmx3|B;YQvfj2AUTI)?9jtHRX<0_&fntkbHu(saxq*OHem?*fCVC7rAw>Fg!ePnL{BHDq-(}{}3NYLecDHx(Ph9fD5;oRZmudpYnNn z;7JiK-<9--8WmH5ZNune-SD+wvg5Er$L+kOgMyVY<>^Q0G%$3YY0ouW;U@wP3Q9PM0CMU$lhT9=g|@jT-U?K-V#MbVrT?D)y~()vTE>3N~}SV)$ zM506~MC9GsWY1{$vL6Ls+K4s8IZ3a}v$I0lLqu#&X=KYE4ea^LQ zzh9-^hc(37s{+f9DzLCk1>dZe2CA=XTfvMr@0-;7*N=K%(dPZb>izWV+kRj13^V5K zwvErHz|fYY4oNfDuIc}&NR>dH8AS1z3jiRS{XgSrx@IIyJX(eapl&D06q@np;3m;# zf3&4j-3IyES(yU@d4=wlYo$bpbFsEC(KWs`9GV0|3(~RWMNkZ<>aUHz_9udU|F^zv z5DbwuAsAw}NwiODXtLTJFbeRmv zeg6qfnX6$9LYd#k4GK$1ynfy9EjP8tb^KvV%U<)6#%X5W7I%`^h~Pka-w#)46-B6V zzWYIzwO%iCgwl>Lgf!K}wzLfOdR_uQ55y zg6UKzOKQ6(v*HRe&_FUvC{Fz{2lCO;Cdg}{8M}5~%gGW|B|Q8LPO}7=>Y40%i32N2 zlbEpfQqUSVf`+Hsu`7*}*-EndN}?ZY3O0pIvAjmotc+w)UcsiipX5`WOvUZ{3_XJX zrXnL`KBO-kM$v^?kqC)fKLj!bdqbyK`>i)Uae8!?HD4a10qpz|VB9V@(I-`^CRtb0px@x>Z79%=phTEn1$UOEp3yGL{~Z=7S%nIP}tp z=DE@{_W;TZlW;8C9>gou-i)6kW-LKd5D;`^df~gVUEI*A0`m;p7=Su!mqURM{;6s3HJ;)V3lOJn4+xa}Hx%EYa z7kFk?@Y7?VF6P;*7Hap*Hi#kh$QrfCu_*e0M?N59j@-r6&mdhhZAnjPN6}QowZ2|k z$a3_Qso2Je z!j=5-P>uI(y5@~v=nmEGk)PI%N_mRNLwYYQ(pRr~??)ceF&TB|6f>6 zBM(>8oJ42G7aGWR8>0uiCOys-3(gSSDN^vGH{##p}Xv#bU&e6Cc;qF4g02)p-2m%w&yeRNqOD};Y8qx?c3kf-ey1Ek|w%@-74`Jys zdi0U;Ies^eC2g-+y~VvwVkp+e(#5{$_TNoMwGlJoyUyr1A;$e4Sz7>a$t0{g}e7(Y+&a?0_l9f-Gn>Ruj z+c*hcah%CDEW`PS6|YjKRMtCR5laMoWmN7S-Xxcud@npqe+r)q&==>LulR19ycH@% zw@Q7^t_xV}-iPaWCH$46AF6_3*#!WP?MOXsx*?*cfXAXc8~b1+Y&oRjzLC$%B#X6v zslGh+e-B`heDMZfu;B36NIQ44XW;lWLRyxOhFBf-`Xp>+?5U#?5=yAEU8D;3N+H33DoKi zQN5ee7*=xf|FB5(TDt8`mkeQmGvXf6j8K4ZD}Tt!7GuYN!0)2U%nrJ#y*}LEhAj zwcMcROy|2z1|rEobD}=mnp1AgDUt2ZWtHxyb3qj$5HK5B6@h$;{JPITF-10xgp0w{ zH?}MNSJnV`;YTyursllkklN}>EoOWP!y@ENZ&t3QPVZ^Z^mm5SZ${}8lG zYK9Ztk+%Pzit8-8P`FOrFu0_^3W-ng8n`Qqdy3m(6BTG?-;P!zo%NzH*{u91b@1!I`gzB!qj)@& z)gqg8NTyH(8)@GYD16(2yfh_$QYURmF|U^%Z5BZL#GDb4_Prhha~f2=-J$@V3(XJ~ zxk>1S7k%I*aDgHVgXc?`ij<(V0DBq+lXxFS6g?Cm^*G`V+Czj62o_E6y(7BG?;IH0 zsusuI45Jya$>}YA#1}Zkg{R&xhbu1Y?(x*op!J5SRPnOV1a)k)Tg7rv3xmF0!8r7#=ZRrX!_htw89`#TS7e1#F#-=? z_uoaGPxk`3N8$G`ViRhy+>;T3qX%0W_%RpW{2CuEdJ7}*{twl51&a-a69tf-G1z?K z@X#Ia>|U9RloK*b_nV~$<6A{pMk=0SHvEQn&b3!v?(YsmcA}v=+2jq*1>d2Y|wjsa(lRLkSB1v^M zD3f7OUA7%5jk4;1HWKqrdNegLCZ7*86ANUaOBGNW*jYqZ6A)GgvpKefub2SmwoB-@ zm#Lh4Gk)PcU}RCHEO56%4+R&p916YQLs>Tm9Dn#-aL3aQE}6sktF_p6=^ll*U$Rf# z{WC_4p&OHWZ}j@LpKtv<0mFxhR0|E zl1(NYbf*4zWIcpd0&s87pQe*;H*vuTehE3sT$TO{^hM*=i3Vbc5g)Tq_-FM zJ7*1t9MFzp538s_j9sVQ1woQjBtWIcd1eO*KGeuZ`rL860`@|Xtsn7X!=!|XxB>Cb zEP9>GWOx#JB4yK;r!;$HJa#|UX8fI+_6@1h}dji1B2Q`FAMusvNo{(Y$=})8DtsNMmJ}9 zP7L?(t9GxOiKkKew)_5X6abYe6fz$=G<4rP->%FxOLv>4hec~vd>vn@3cJ;F4ouQ$ z%=y<FJk!IN(I%Z4z;{ z8eK`2$=nZk6cOT#Cq?8dw;uZ%6h`s+gOjc91|J8+@X;{He>1}$}Sa_$d_(ZdqwmRm;9spv{=nheNGXJI35RlQQA zVqh8J$C(%aCYYF+ZSgm=lRS{7^I@9tE7?<|7g9B1d|fBaP-5DZRpSvzL4x#hvPA?E z#iV~@RfYNk7a^g$+9$em+a)nNqo6*wZm(6FyXyy4DwoGORItPz6)|$oQgfxEPd51) zmIq(rTekzvDAC{RY0@JosINIBIT-bVq9|tk3H#QFk#*_FE=Lddrj5$m!k9SB5jB@u zgaQeS+CU*$PV{<0r7vQ#R?zPL8**7_4{}AEu)uE=t2H#j4$L+3t7^@XW=jGETGDB%DmEkB$t;rz^H6_xD%@*>gxRM+GPw)i zdEmKA>hKWm8lOfug-jaX{=>2H#B?=X3b2>)rCU$4(F2X}x9RW)MaL%U0)?JqJ~(pu8$x+a$>zFAc53_G2^=utQy!Xi{H zZ*k!k$;V>v*KZRON>WSK3S(Q$Cs0;qqz}d1S)Vg>5v-A8(;uO~D`59YO;pv)5B?LL z8L+N~uK3bqHr;1Fp?-BhU}C=TG_p{4q--FuXt`9x^lTlc#olK1o`+KXFXYV#3ra}i zQ)ot6d=@`Uqxsy?hRm7#rATQyan30MK8PZ1J$}NGRAfZr_U&>7Wx_VuQkk3j;NV^b zLa9?4e2zki`JJV|$l7uDhyC`Ghyz`)gTAB1WVgec_ME8EH|$qt8}|KY1zAKY?VeNf z)e#}7{$5qHOb%$Yf*K|C+r8_bJl2BJRO_J3a64YXCPX|~FGCy1iQMXlinLy2>p9c7)$XaO&=dKvh7YaL749ltE%DOX zO`JUGPtN17{n9e`m5b8sLowrwP6;syAsH7Bwao?Xt6!kV_{ z6?>*-to2vt+b7;)oP5Uj?8U>hTT;+G>l45*6#ymLW7m^@*XApse7Yy*Ix8+@N^rtv zT(WNdEkGy?xnIBg;R2rG4X4qo04oZ2R`5M!Emk zH|(8DnXo^uv^y;`O8gz~wJVny6Y|B3>7GhQuo#X;#rn9_V(9Kg#!@);@e6`uiJ$B@ zmKnzs9cU+9#EktKVB%nNk{C(0fU#``E-kZo!*R?aZ$Ml{Ecm4?a{z(*TfQA!ZWQ=e zUt?do+{pDGs<7uSH>QprRjHOhInc|ae1()Jgl=Cf{dFvczECgiA>f3~Hc!>L7Gk*? z;*45vAAg&1V$M6`)!G>XJ*aisucsqb!8~=-G2g!YHse%(`2hR&+nCGP3VYja#^`WS z1yra#wpu|EN><1a2FXKGLzep6KJBTVW+XXjwN2TUKT266SsG~j)KyP2lcnw2K7B_$ z%}SQGPd$~x#+(=bXy1A}yB;1VwL1Lm)~hWc8Ae7{|a6p(?yu?L^lLtHF5})b=b*y<`>xF?--`q)v;#J+G+oEhjF|= zqr&cWCyO$6l0EWHqc~iA5-8k`VjhaTOjT(U8@~t$eau)VxVwH==d@%^a1ESF3=4T+ zXMUn6Gf|ac5O=_#P*uTT=sFdzP!bGoknnKHvrd=+e(j>1=z)%A*(R$Lb~FC8Y4NS0 z0g9_gd8;ZM$9Tw|)A6UV>&jgBQ*=j5!JauzBz#6%sI$3lYja6bxo2oInCOTRhTpn7 z6AcxePh^!bwsWq`_+Xlk@2CX9dC+d?)g5Q>XF+aA%>=sKSnDqw4eB!(bs>^N_*Sij57Zx)9vne858~O#@kok1$*i8 zjeYA~#^7GFchR*&?LtGa`0V-`PvOuV&ad0;_wF(-^Uny`Bknei^-p`(uD;v&AAk36 z?HBGgF6;c12OOu@Ks)aquP%Hy9kk8q<_ zU(O031f<2l<$U$F{m*-$b@#2bf4|pg^uK(f{qlXr+5Yf}cFTQ6$#EqD;fzaO(e{Fx z;Dgo_CL$E9bY594u)Y2(`|=g6r7vgMi512fxd&jG*0U1-;pE<}1T}WEH%fz>;I~)L zwm)A1h5hj!JLi5lz?awBqwY6O@ip65-fs*}FMa%=U3(y-m;KcJ#z{RT3#WT_3!+QoEsK=pgl-k^fD%DsE`WyPT!KQ${S1)|?+{bY>z{%CW$m28mF&KAnVMkUrQxGbr06)rm~k}yIRFY`C?tb;8Z^5w-I3t@ZhQu~9y z8-xAdEVVm402t0p+9y6>^!Go!)E*=E`xn~N9xw)9IYoNY8JjG12QXpM+6F?IsU@XM z567;c+Hjmcj7yg5hEm-QpQK8el-dBqq3LJY)o?eot4D%Rb|Ov*c~HBr8LwLM?<3D_h(%6sI=YrQ~QmFjZ1t% zJO2?Qk8@k(RHo5vbO`lfR*N`!8N^~gtu5OXhj3J3Ng{)b z0#2^Xwy$1kWcz-#=dUzQ^kv&mtTZl9|4Wa9cF#wRll>Q;X%|1rrlpw+75&&u?#s|b z>KQ?pTOQgboIKIZsa>i@JOa)aIWON&s9X>|rc}`dRb)a&s=qy-Q$;JJ&+w_pUkT=o zUcqGD-k(%ANQZOpjJ{{_?5GaQ2;5htA7Y49P^(m( zQ+ zW|dKR?(ZNk7*c3q%Blzs6UcDxprw$hf)Vn}dQR>_>5214pd4+a5$CS2lyF+OtApk( z91}Leeq)s}JbZp{h2K;X8Z7lv!3aV|SXTQ+cgP_73|C~INj2%!mm~F2lIE+Liw&9( z#2BV=87K?3{7X!cf8sw?P$XWYi5S(nPm4iS*JRIq!swB!7svVKO41SQ`xIn`#Q6bB zEfRN}z2*s{*q34Ndjhp^)T8!ao-|JGH-z{dWd^7SO-KoK69QHvamLqX*iS!6dhQH+ z$CJjb{@h3H%U2t*tc0OxNBla$V`P`)vV$wv9a?P+^QE8D`Jg@QY2%7s13B@DDbJwO zMRYk}G38$mwx535=y^;=q9j9JOoc79Dj8!>v;XxpwExZqyUR0R`_&D0!81nR0Y%qP z(Po;#5)vB5SG5}mE0%UErOu(cm_Klhz4RHR5aV8Z!!u0uuHnDg#y^ac&d5mSuVeu; zlYCp1@bUjJ&Y(ezq#Lm7TiHWvm1acF>mrs6;VhNT)py!g{=*pJ|G31y>mSAdbIpD9 z0plLsb!K$`-G1#KMn!KCNQ*4|z&>Xl`&d0Zw2JfWA#03S`o<0i?R9I6;k_Ep5om>` zGgAst=|yy7p6!1Yfqd%K_8HF_`F&^H0EcY@spAHr^r}S|w`V_V96RzUq0iF%o|C~d zjj&Z3O?0_Z@r(*4iE(L$`#uxTS;C2fEA985HS+p?nEHMZ-#6>dOtREF6m#w1v^e$gf za3*E@Kuzr3VNygOI=F-V;acMaf7%Up%UYw)pqnY-ezITHS(JF+AF(- z0NEAmjG=zhZ->{R%1o-Y?^tI9b87Ao=8*M<(h(j^2z6Ilg1NR~gZ<$;V_|xB;GliQ zdgGjIwU;q;j3jK;OD&(KoK-{ZP3w(6_{zQ-y zL8xWJT+of}4cRi+uv_QqS@zuLjJf`kZ?Xd$jMF;z(w^tMmZEaIcmq`$r`q#27{x=j z4puZqq^*3%5W1}CC}#`{EQf$^L!z5Xk~1LOKBwHcY>?7ZiV+(CDr@PI1w#J?(9Sz@(){qx31|EY`Z)z2Hpbt$)shZG^khp;}C+n+vf zjPQT+XFK}^KBZvekB+j9r`1Gaj`yrudgL;rqa%R(fD(IM@er{p9P~>6qL)7pjc9?rCefqrsa;B zXoSw-L@BymWv_nG7|>BNNr~&Y%Kqp@MCJYy?UolwhxPLz)gAT`21}f8q;JdNle$J{ zAIW66SK(#y{&q4;s(7ywC$Z>Y3+jwG>6AW{;u+_TkYu)>3-js@hE{sjHOu-+a~`5X z#v={LpZlDB$4fxJN~T{Pz$|C*}Du;YA_FBo0O4Agx(KOe`Z&rU(01y zH`mc#Ol^ggM|l3q6O|Qg!#?_NcOzJV7gvhSz7k`H5?&T${ zC0Dh><{k64lHe?9ZKky5f$`jc1UgQ!_rGkMJb0>)flm>D%{h2Q@6s|;Opy`s8T68=%Vqelz*(3+JI5OXq12)~b6vV|c88zBA# z2LM);49F}cJf`3POL&U8=&va92u4*tRsZgd#tFT0k;eoE8^jcwsIMSu#Hz2bPi{1h z>y(Ludgw;NDW=+!8jWLp9qqbCHhAYeWdFU<818@edi$eBV{mv%3Wxk;iKTX`s~5p; z1yw5WA}l6~#FAAl&>LNjlV!kr%z$v7a;F!U(p#n$F=hif=!KieT-7q6&VuWq|FPgs z9&ccCN1CN5MXh7XbNMWtq1)CbBj>7hvW^_SeLEdP$re@ig_WSu>ohU zd_^4_WZBY5S^u>uG47Y^)Jsk{&gJm0shqKPedbltVCE}Ec6f?f9p%mxVkeXcTkcHY zk{~Y*28?O++emd)l2KA7EWUA0AL5YY5_B?O9v5uVFMKjVLrJ)ipBbtr2J}SpWrt|P ztCQ#be|&ulTvSE-KfA25=ot-cdnOK`?fd;9(Qe00y5GnZ$cd2aK} zGc$C62!?wpN+j%u4Q&Sby^fbT-4pmbU&6<`lpp$1>O3-!toHhK4`|=1I)&PH2N6a2 zz_HV5(SpS@EXL<@Pz8V_F+>&9-;K2J65PTd^PzhnJYERmMSGzC-<-l%?ZL9dEnv!% zTjWUcJxj>OF6$_q?&*^X7WbTkAb< zt9^DT6L;3WC=>V8d)`;?`RjVmhw42atM~kUz30=$Ggd0?a(E*F`&rNMG}+x142y+7 z8Uai{GIEjx73V1MV|fPRe1KUOA^B{?CVsM8C+6QKL>};ajAjyA|7ZD7d~EE*i)e7-v)ol7 z^$l*1`L>Tlu?M&zKUg6RV7IXh4;18)QGJQW?2}qV9;KCe1EGCT#w%bb!z#w}_rZjn zG=)3&!TI@4W4>-5X!GDQerO+r(t-&*V84_UK^h)HD06ptT5}5d%QQ&(NF!dbUn(#S z;+ytkHfZMu_Dd}T$M`Af*ui!zfMskONYz zgWMDXAt6+T&Ly_DM})9TY#R|y3=^&vqH_vFuF8p&3kM<>oyNPZq__!IQq`ra30QRQ zyq6ONtgZ)Wq0yU5cE{6OiO9KAcDJFoMX~(y0V$%{FH|ewH4c{86GEFp$G^*?zmg(@ z&kluq;w!8`l3QRhb`<7(CB=@2JV16cX%+h*;CYr`(St&kLI~-jD2&fWvDF1Tw^!B7 z)%~!8Mo*$eOo-cEKl^)?PvyJbTtI=J9?rk|3O?wsr}IC*f}QbNsIXFPbh_nKtm!&q$EBETu+a2B?18dBnWXJa8XA z7##5hm2rvVN}Sb=z=b8~o$TsKB6N{qDh-Qu_C1jqsJe7#2M865L zd%AdxL*iudl!m7##ZwZV3h;Czy&X z@n(x1mpmjE2O{B(!Z^rANZu=Zt|RII<68)AW4f(W`={f~5nEW&pfK6}8dW+RTMZ~G z1s5{NE(Iy1DFK%@@6xTBWF)TGi6uh%IEAtgu$0V73dMED81zEyQ5A2pYZ$&k88|D# zD;Eg&2VZbd>QazP<#t;D0hy49c7Z_6lNWDA3LIwzA|way-^wuI84wkOrc6c_*G`NM zg8$UeB#*IUOM4)fY(@L2gg^8VywSH(i>G>FzUDMUnaR1YMsJ7rGHj(bgcb;lj{}b^ zKq~q~9*aDWb0|%*4O_ql^0X?J*n~f{IU$%?>6g$yGCU|CGcPvB%E|NPCnOo?elh6Wf@4wgj>E;nO7S+xMhU+VpTGw@`?A+**RNO;OfsxL!wJ z{EKiU(ZdqmD_fC*=PCLDL64CNlI`O1uEz3ON4^t4d3# zHcU-$$1Y~muGp;vA`MA2iqQi)M~$mCm_H`PmZOBmLXuE6p?)zY79r`TKE;1JCdCZS zC5%r3w}zs6)QKy6sk$wv00qKUXq*blCK#>IDRJ7iCxzu8Oa@X`o$=jQfln!zAMO4oi^_CIU=-sZkL@M}>*tjld=%c2poE6T18V(XpW|DID9N zH?bNZ=xxFisJzV$zTuG6Dqs!01YYNd55YfH$QvHUa`vwsd7s0Wr5yc*k3B36O-p?q zd74012t8--j6rn)D6up_0MM|2(2?Y)Edh4`AG7@QN+6FELeU|<=Qy?r)*3#$5SmL_ zO#1uCqCFN2uj*1=CY=dP=-1&^L9Lj=))LuNEb;(^kKs@hSfIreYS_nJH6UYs0r?<7 zb(3}qV!%0m1~EK&0>tpID?H$Psm=J$DCb>5EQv{@ACvxvewv~P)lWA66s4wm(rZK$7OX^}qLQRYSQdCNl;4Y>{c^u7{^)n`0xhS8h#>ROWgLN!aD*}` zyAa~Hh`;t7Lg=iNQ)xh}<7?DVEw{ zZj9=>(d@k4NY0|Y&Gb=!gDjVA0z=8g(Awnt*H0pDwU!r=%TLz`WJjou5T_dDk{(R) zmm|ZKOVGkC!Bd5yU=AMu)lShVzzSqK3#IUA#%vvAQ|mYhDHM(quLQDbAzz4hk|}~zOvbyIHIU}X z6BXG&7S>*VP`R}HOWa@97;HoMl1sb8)`NIj#IK)}+J%z1!)}1oSQN1k7PRO>-t82Y z#{CQVL#J@_G~rsG|95C26`G zI~oKG7#5-d)I@O0r8u9&uWT$H#pwuiZm0GP@*3Zx{mLGsPo#rLWzIq-(VhYAhaM<5n??XU)svbS~`zKV` zm_7}$;&g^Zu_b8Udz1qda}UBfMnEM#@UF7caVwO|UmJCT&pa(f295FI54cQwqV;*0H~&$JPNsnt zsKEjIggKCc7!+;t2+%t%4}wswpaY{XWJ}O;Y*{Zp^+zdmN)mEW9zaB$(7q2q)+}0) z4pK)(J1>|f9SJSZM64ZE?xiCj-3PZ;N?cW5Z(PcrL^T2uA`NXkzWc^_62JVT6cPE+ za7@t#hzf;Dpom`seRMXm5;jqdB~3E^BF%$Ehh?brrfi4 z0PvW-3d$aAnI=y%s2p2uO;&tTv%=9eP$s%9*p;vpNsE>%goz-qCgB}J{|dnKD{3NQ zzI`4dUAoBc{Uk-0d*$6P>V2qJ}+)(S`QBWI*R(UIO%EnpN$JDj=bdKJ@Vg z)t6uAsb{4w?P-dvnw9xg_+6M`EuBv*cIw;>_+ObX{;$$5=W@?ksYR#hb!L8~f;gb_ z=P{NzWcL73L?U$sWLKj-ew!aUE47hIz+SuIr_{9E2l&0SQh2-RgHV9tkPsq(6RW9& z70A-Q(6H!2S6)PF%TM!^pAm2J8J~ckwhq*R1qL-g9OB4pcU+k%65~W1@{<#J$S+b1 zKlQWJH1^C4Uv_I<_7*sv5Oo;Y8yVR<95@9fB1SSlv@UBXHMfiE1&0J{yC?96f05dl zO8Bf_q~2{Nx*+~3n1D{c`R3H^nv(u6*n`R*LJt6Xk~VV)KlTe&%k6w>Lk4$eS-9~f zQR_BDFik9`i_YRqzakk?0vLx_oT;Z|WL5@X)8Aioq74vGQVipxE1nW*pyuvgM8i>R z(OOQz_dKLx%|y+JR?;mM8A6CE$ym3DR&jz~PHZT0#AEGD9bi*>c&uh_?$GLQBD~)3HqfeSvfrBycB76JjDB- zm%`1*uk(k`OIH1u0hwN!XofDzy1-)cX+F1EZlrA>1ADtYI-KgR}n2ed8CxnQwWI6GPwzUM00_xA4qeW4&i67PEGOWXDo1WrNTz)uTX} z{gK6=s6v3%`xp4!D#_K%4r8>T`a-mlxDfec)nUEay*L zmin|j2Dc;h%OO+hX{LrK zvu%9HRjET1=>{xZxTvh5_7%5C)3l5I_)Ay8F3(NnJFZF(ng?~^mTS_~;W_fBGkT1J zb@jNsBQy4K&rFkPH{RmZ**0Zlj&hsMRHT(T?06%jiDfK^B*HtX!dKIU=8ne4@i?DI z)7Dk-@@uHS=}q4FI?mRL;k~a*PnnzQ{I%;+&+r`O0Cgt|%M5~+MMYZ2{`|M=Qnw!8 zrwZ|#3yX;SP?oYu=n2Lsk(z3mhGjdF>(NNb6a!y6kPo;ay<%=PmY=EJsYW~|zME+W$P(ik+qJ^7Lv5$<}T8=xQm)oM7YcS4+dpL;AgZOX@MYP#=L= z4;DvV-9gv@G|w=tjCKUj9GyhxQZb6OrkD$I7JU`w6-oQ=2n*<@-j%#1SvkU5FtEm# z-9pg+JE{DgTT|as}FgWHfIK&V1<*vV^tN`Je`Kgj0 z`U~44(uwYfA&>Xsfp;MDi{9YLcR=`qy794hr1+lGD1#T}IRFA6#AB{o*%}~-ND$f( zj%6Lnhi{46f@EHCM{3)AmNx-(Kn;j1m9)Xh+;mq84_=ONCxI_)mn3}gPIskFnd^VS zK0q&>p@_VA7+j7ZJbfU3QF$)fBtc*W{;939*VmH1J-^|Cq<=9@6Y<}o9e$~v{c7FL4GJNbf&>bB~!#d_RDl9A@!}?hyT$JT$ z&3KwWo6^*W?p>I(Y(`f4u+yJ~nJ<6EPx!OwsFCO!x=)m50CC%S1q(*u#UX0CorhXj z7glI5G*;6!&D@peSXctsVUC44nzjJzz{@ei1QRb2a}aG#dmh|?wM%QBAgDYIK#o;x zV+2k{#r_@J%Mh=KPiYltW2kxg(@}}^s_lP?7d2pG&C}xf4-HuFX76F_u!>F=r_Ec3 z*8ErAp&{$h{OGT@s1Ev;TOV>VaRH{%kYxv@p>oP2h^7nwsUeFnXD#Em8nW&|Q|f&S z@6LM%umtnSPJBWDn`u7Tk)ID>Mdl_y@IosaXwL4;-?6eBbElE~x|Ow!N$d))c#|ra zjIkhRz1P%)nVE2eP@Npe+L?b^!N&wLyJ2^SHKSf2@CX+b3`q3#rrX(<8?i`p@LArf z5$k8Z+=V~Zh;;+}iyE;`)~|3|)Z8y$oJj#jE%=E>EG9b>i;j)Zr%bZP?E?iR5+}xG z2rWz!Hd7nANhs)es7LYM|6}nk!UgF2l8<=*#;ln+e*@2N%w7zih`=jQwp|@88KDrM z$jREd2!5e4>jkwPEwMN#iNO+UfuHdb>l|9v$#?WrmG+-Qq$xJO%b)GTT9~&5@!b;Z z(B-Yij8NVhZ%AP3`s^jyfvh@NtmbGcqn6qCL4dAp?pX??qMv`{8cJH%GeuC zttgbEhFU$|m7xQ{cep!<^+Cwx_8{bM@Bu#=#FqLuwcO#8Wj4-yO6A97cEtQ$G+!6Y zx|kmx!H);C)&V)5e6y09!~Y6KV>!Gagk|GrbqH(MKF6MkyYI5diXf{-eMwjmE5t2R zkZ*)IWo{L(3}I2tj&(zTn33iKDS^R+Zo-nx<67|o`dxIAztn_vv&8_bWWOm@h9|{1 zVNok;izN@^`a-{=R@A>T;zMBFf_t`%vo;h6y1~eY0~E^RxV0%u3ZW@6d^eFz0O5de ztzS4F)|5SBzTBI?-;})W$n!sF?>NN`^H?bpN|S-`Q|sG`G;YwT_a3i z5KnDV@)7nH#@a*~*v+(Bv|ljCgeY;969Ne3kb+UoSVwctDxTepb%>(X0Zi93a&WZ+ z6o7sOYQb3Wp{!~%_Bd+GOtPTQ2)|ufHzz0F)vEXNhRs=jjM{+atY_PG_$;DS@lAyz zN}JbKXf>PIQGp58OUeB8<}4=6h)z#KHY_EJ*mSKhnICD+QbWCg>-6b1`h-GKGH(;k zdYV6N!}G)0hz?Ko6~f<+7RUi=OW1EjFc}LSHY6itwyY079L}Q6k4EvU;Vi|}hzm5DZB0u|(-dBf(R=q#a8fIvTOMC;V`e# zia;FrLLCIHPgX!$WF`x@k44LG#&5P}?W2j&fh`F?e%eQf6VWHrQUuv|Roaoz+q_>i z>k{p1BCs;~f3QN646QtjmqxSR2|*q~<;BKYFgU47Yl(9`^+V_>0aqp5m%g#lMu+h~ zQOvM|=auug81_Xd!BcmP2S`ynEAx9X5WTD3=Uv*ccA+%)yg$c{VI>5Y0SX#x2aKh2X<# z#YXB2{$LGk#Sc=piFZ7fkeibJJVrLOFH!rzfED33wVtx*UoMxb1GoHVNTt``utz^-LNriCRR7j+ zxT6-sv_e1_PN%m&gwYa>9KmVa6!}gFiHr3t?@Ajp;9%6+Z$$-0CItaMFQ5WI-Vyue zcvVN%(ou*$VxeIXL%jDQGmCW;k3D-m9$xDLBii4X1C@L`BJY3_kI6R?qQ9+v8 z83icPUi4dCehbHwkfiNsZ!&wQ^H1SUsVws?8(&6XW*#z+#rjPl%;z!kl8-Tsy^-N) zfY7PPuD}+lSk!KrS5jH{`&=f82sl;?#MkfjZCf4jagY z2K>;m)*9JUnpFnJ4MP*gsADY~2OK+3`!10-SZ7Bgzll(4$$oMcxP(YHf#f&ZCAUSq z$N3!5njx#T^)FE@_c%<-?X8TjHxStF`??5U;r)xKasF<`i2Bore*Y2O9+yMU9_PLH z#K2nr#QjJh;thOh9~NajAl?Et@Z4T_TZ=a$Mt-IH&J+j- zJqE7V`dBJ|^L{M7?Luw#*f_f6#G|GndMkPHK2##Re#W93utoHtXrASvK%eFYq3H(^ z<{+v>G^zueSgD_M?5=wt-6Ri!FDXvJ(Mxma)5lhF2N)av!^C(PSsNg$_au;#y6Pg( zB-JKwF?(_kmE1PV3;M+amM?aCrXEsfBiJB2CAms=Vd0RR4)Z(S%LcX)#Z2#)ONXZD ziFK7>5+d+K6%temWZ(KPXn4Q_iLxt@z872Fw49pBQ{q^M4w+?8$iSp_c%y(d39Bqw zIh3aL?*qpvE<^tTgUxq!X3eZW;=nhL^UQiM-#LP{;g`BHsmT>O!YW%50tRTy#0Az} zJF@04_hlA7v4BZEKSKtzVzE#wJ4+m)#=cF#8dUAV`%pnN zW|V@Kle7XHT}k6sLriKY1X}d7;=9k&?$EAb&%MXl0Gw(BtNwF7?HiG;F=ZnS`+roY zy)CkZP&Q)6|0|mV*?

    cAe#@wgREc6Fp3T}4*F7fkSpfl?d#z(qx*PsExfjjqqW ze1}jFi3HzA0?zmG0^|dn3Y|ru3-%TS&UsqiQLXHrQ1i?-vnckF}vdLPc`#|g171Uhe7p%DFGs0-6UHF(CBw-oZMKxkADp0+qP*K2DH=5KV{8fAQbaSvPZ94Sy<;#rV%g!rfjh{Mjc#&jvo- z&tYKoeyGAL8G7K61PFkumFXXUDtdy$U_SFf@kGu1?%#VewY$-qaO#Z^ z=0VtpO~Ty}=K62mzLCNW*@HJUirwuqdO$Buy~5}8V$FMWtk)aQ6q8nH0)>cU6so=P z9K?rO7Lq-d>Cmx>yrLKU5AWRNcY3i1$3;*GRg3#Zdn9Y}l1HhpyD55_j0+q#1X}VK zCqQF-<2C7J>L>Iv(%~Qya|e0xQM}Rc`wp9!-VJj$W9n@HLxP(qRv^8Y+C=U$MI6Q~ zgn9#{DHR57(*Y17V-?nL%fM$|vw|4R_o)~1m$}3zpqFO3qC_jIdI;9^Ey>?bYc#1Q zRLM!QiiB{S0I1js_1_U~=kO7foU5cA;FX9g#MHl ze-wkayGR$hTmJ*dN^R&-E6D{0O2$P%>NW2(%$pV-^&s9-1MJP@1%=ph=*w$I8OjG- z*y;wBXdG30N4Lt@`I&?%G9u836!DD?kM+}z-{swsF{OR*HXoDB`ZF^Si?K*Fp}s`E zA(fny40q94f(R0EH93zlk^86}T=BZYXdcubv*9}Su z^r*l3Qrw87uFNeINhXi4?sQx*) zC;oUUi*bAagi>Mfu5qLS7+51%urQ?TtxOxYRDgilsEWJSP=6Whe_;ziv}$SBP}+Ng z5W20MU5ADo7Hkb6LGW+tqS%t2i6(?`-}(bXrP)scCu``=AkoqLyA3a8y>5SlBbPm1 zm(CS$59um2B3(aHlZDuWPBV<|6sT)tq}MFSLxGG7ih)2MIw<;8dj^o=Zs(_K#a%Eo zJDQDCarzZ*^Y}Dvi1Ta%_&H_Q_Xr90e4YcThRGih^*v9%wK4?P5|>+*s!r8vrnwsK zkNy~&crld*mK026vK-V`)Y*|g`~ZtdFG4+d!)){*q!4n_Su$eLF#0V3Gs^f3$)GL$ zFXo_zhWS^tz;?WLaq%tw`2(y)<61S+usuKf01LCq)nW*f_}vFs%hbXvUMj(%cg49l z`cBQo{}yd?790+AAB|V_Y9Ifnc2ZkwH3&U>;52cOZ_>0@ysb23a&QUWXe^z@BsaTi zd{2KC8%FX?C@&fg`KAD%Bfs09CG?tp)p%18BZdp)=_7AmGY55=H-J$Xfjj!#~VBhrO%g&!t)1|pckNjaw?JlmKcRB63di5`;b z^EiJuG>$pv2Yw+9YlX@c9+l1_dL6tDNl@)6rq~KCy@-aaXs!MhTztM`P+xytR6{cQ zenfqYP`z42J+K&Wgc^0-8nj4Lg+8bRw(QMH!IYRZcx=>)&j5jx_2Es6;R%T>e#Fwt zzTOH8mYVeS_BgTH6x3T(s&A$lgUka2C!T z8LVONeo!}_AM>_^b56X+ts3^2dpW z!G%EYvX)Sw!t318O8Mw>G!ncFk6LQgD$+Ed<&`BZ8Xw2(sMVl*kVsD;O;hbUdE9yoy6Bo^iO}IgF zN2$WKFwlwq8NmoE!^JRBv?7d5h|Y8TB!XCzv_PaGWDfqZ+pVEU;r8(?Z;M&8b{Ev4 z5BRmlArQUA#h?!T1WrpPY~iC8{{VqdjubCt;#3o&Ovw8^ zq&2+W$3ZVp>td>p&83vZI8{O1X5uUcX*{S-21~88u@q}usjVOJ0k5>N#PIE?#`8H< zMqx5l+MSn4{v>!E%`J}e5d&FQ^P?AqU~{bg6Y$JO)VH8jk`_<{B!AaGa&Vh}PzRjp~5X zb!38q^f&N316jvJfno1zV;v$NBGR=(=IPtd)QRmaE2&!#7~L9u?5MDU;mXbZANZ7t zF6h@>i2R!V34c_^lGA`N4(rU&t?-k(gh;pdpzW%68`>MIuJ<;IdqIkh6KC>o2eD=j zVfUl@IGpYRm$zJsLu6`{Td))|cl``PMAX|s#O$0!pOA{fyr9hDX@MjQ?(iggfJz$` ziju@;X$tl0sIgbTFBE2k7gF`8JhM!q@`kI0l#+(ChiG&rX>!h34zD~GXgKb?UsA(%O0HP2K1SYD|hOQtSK4s`U#}vfI z3Zlet)7s=%{Ij>i$kGd8Rhu+Vj3mALIU3i?2I{25y6KFM1`wiY$S1=Tcm;+fYD)5` z)1Vk`9zwS9RM{@AwKCG!98^l%{3gfdRYoBMcdDN~8u{Ze;TTUlFvcg_FyR>Ctp$6~ z#uuFg{>CFuo^~k$^2CMO!1&&&Y~zc3XAWy=9&(ZYn8P9+aWK`W8Vr~4z2;))hS!>h zmdeB)d2z&PqJ6M(6ZsNx@E7*cMdQL942p4LKwICjx&z{ByIZZDAQ#~DP%>$66#ak8Qv{4OYmjzG0rvJRaM-73!p9&D_*;53eFUzJ21YNW`#FAVA@4$&rB{KvO|IxV6 z0^Q66g0Ug61O=Wa+~T4*>}--(k{zG2Z#GXFNnZ|h=^{dN5|U)I$cHMmfaL(f&z!AY({g z+VjzIS`hr^fD%FB+)L6F!U8fL5S=W{l13g$Q8E`AAIF4yzZ#)j&daDU98oa2Mw~sx z(kwI>7%`%7BTNZ}7)vyf1*DMV#=wivAD|eEm9eV{FoDe!a#JGCga3OtYt@h~#)}YV05FlhqXNh*C(aASWQ2CD7}84QBDcjSXZW%ah+%Dhp6?jJ zx|`?!%&SH~cJw^+PopBncO3>3Tx3lA-3OpOf$cGBf3b2mMs~NRfV1zhbRyJ{#~UIC z(I&fyjMRU$JT?n6MOYr#=xcEZqXUvRm->WKewulDtpVaUqlM}$Aof{ai2vceAsYuF z0AzZ=eRCE+P6y1ZaP&V8IHJ!!+izG$C7o)o)&EQJ5t<&_iu6C6aLPBT!|NT$>uAAt zi_yrQ1U;3A{fUN_79kTw*>GrymJb0^oBA&c+9nV{isb6f(YkjBsu}`4bPt40nL10^ zT7vJ|@12oOnGR`@@zB?Bz?htW1Os7-HAPO?gpNEEB7-86AcdTxW&|tN8F6Sq0(Ptj zF(m({MS)@ZZK4qv_$CA;LJe?|$Z-tDxufL0MT1G&iEyH@-NQpEt*h;<&_jaT1Udk7|j;rEo+?F9#Ti?dKiWEUV{3~0=wi&P<7G2p@Y zM?1sf2~x!V!7SCjrs)4X64Mka1wuB2G4Ux-gnVSX!h5umJT16G%eRFWPAhOd<xSIyQ?vuO7=5C2#KiyJ3wZvmgoG=P}#YKR*P8;|)^M*CRO3=W>=^ zZ)3vcb2rQGm++=9$A1`?&j->$J+gZa3S(gPZ!o~ZgMuS|P9od52I2$%_7ThgMnkqi zdg)`ZKIJh4C@@0bc1P8}peH#K-1VEOJR0-;}!7E{Sl8_m9iJ7$V^WhRk zMTU8cT*v`{FB6%fvgGGs_S^3`gv`kEie=MH%%&uZr7*vd5okjV>>J`*C3sGnLx zmOS-^Sb0ZAEXABO0#_}xos$!C*UMD!*}Oyy6Q`51v#Q=_gw!7 zYxa-4rjRx7(v4uoDg^2%G>#u2rm|v?giT1@dXbtzZ+XbejhdRPPV-TZL2(x9%(|q=VZ1>lVNE zIEx-N81+ut=k+8tvH*BMDLZ>3S()6(s&~ahou|?Bc`jNZ$cUS~6bdWBPy2V9|HIc= zNFVP!cyfkfY)F7>nf>AGB-H9((6Jvv=aJ_|@#?%QW1#c)6GOd69)H7j zAfKS@{tG4;h${|jZvFINTFwxqSJu;*n^D@mQ{2fh3c~MOU!H&0%d-r5D1_~X^Ea~& zFC|vV046ylsrTATuL&7$gN!asC(GaK;r!$P2yWkRTzi7GN{t}bOg|#C`AGKOgqUX- z6en>$ywXsgf)5y+IFF$lR1>tFL=f{aV^~DA5IvB-2dVfL0?!*7^t%&+GU@<-_6e-8 zH$RCc@(=sEQ9n*^(P-)_#pwZ6xD&}hhP_@#Cwg<3kwc*z=q25<`{Z*7pxf<4Y#Q8? z1FH2YM(H@E`sSgSjPSWNKm(!`i_XJeSTT?GiqK!hyldVky%1h?RF+is3epv#YS4^D zoAf<^{T3qrZ{{O15NhBWEFrZ0jFkYr^M0X(p2BjdJ{?@Fer|;g?CcLvWqdNc)K!6+ z)j>0(Hw|xBm-gGS*5Fg?0T8N^-hkF@1ld+;6?2Rw&mc4-mOLHjw?S_qn%Lu%h>u`J zd09FKvw33ae{#D1%_ORI#WsZNRdx>E2iDpjT9MhvatOw~-Vg7W=<-6`|$M*v8~bvVjmYQOR*NNqf7$fwi~MG4~(b@-$0qx@Vh+9N$|!j)n{{_B_oW zdYZK{FH!h&_?2J8eI4j?I3j%xXa_6#>ZcJ6|LG6B;%OEe8xlkoxA=TOb}gr2t102 zodemJgptbih7we1vtQ$z#nFQ3TT2fd#MLPjdw z?hkIrSO%Td54&Hty?D{aJ4|AUElf|Kt|0gRzxU{~8N6r`vo+SKm(;~^ zGx)wq*v2w#G_Rb*3ak-hP_UW%2!CiY`_A0>Gv0OzD==@`%4bhu1A|}wS`ZN(bQLeV z($e{NQ&``)i`dr}sAW z5LK_#`_=r-XW>xy8^OOoUdPQt-r9Sh5}5U%AyNB>m#Oyf`l@XBlbNtA+mg;!BcyN(GLv>y0S{0~&q&+pIhPYZ=3b+NgvVe58?Tzr!cxUqKG}N|(nZ>9ID`RtI0-{|KnaLme5%hyp8m^Ls@sy6+u|JEmz*wnfc9hl=Rvk!Rp=@z#UZ zPf`}q`W`jSmnHKT?wQ6Sf;-)p^|hOPbrIqM4o+iI`d+k1z4z4wR+C-0GZYJk*N7*U zP{{uU%(YocC_P9|1~dSpR&F9ff<~+jl3|-rS7<(Caw&c_va{-N@U`WZkX7MrsIuqliWD;Mq(vr)=b{ zX0s0F-Pib`7qNfz;)nbO{Z1F}Eu>Xw4M;)PRvTYBV+Wac;Op@9GTa0PzUpu@?ueM_Tter(zo_-&D_!duLt;}Cu;qT!she!$K;x7>#>_Y)07 z)2r}wB^-IVQtH9av}2 z5f$N9@LT(5S&_Jg5`*-Eh_^Ku!ct2|eaSmUm4PgMbkv^Gz&Oqel8A(D|(4Ng8RFM5W$WwTPx=oU3k=rVMxG($o^juXWJK00={n#LywJvBN(f`M3} zhtWv;w0~;k6Cl@UWClHr$IV3$XJI3$T5x^B5$8?|>H$R|#(UC>tV1(F<3g0wQIz`> zA4>9IA|@$5h6>V8|4H&7Hl*Qu_fY|^d3nyx!b8}4;E^OtnvhAGx(S(NF8q^6PiHY9 z3O?5pXj+^oWnTI&pFABrbm0oM+^b@L3-gOUh@KLAC^c*H5(n! z;*1X9Uf*}n0dw^qJZ1*#F>Fm==-(iH`yc;H37ud;*Y)Ey${|GHHBa##xaos{R@F8+ zxskl259~L?`80AJe`7Z5(z39%03^M(kX0={M+6eso}Zsho4^0y(j36ieI4(GU(*); z*c{f}9Mq0apTkYExXA@o&^8i{?~}I# zy7m_Z=}&-4$f)8cP)*nq2tQCgJ5dZ&vA9z--d3LGjU3qS>L1O!IAFc^In0MTSZ4=i zl9zk}RtF`eB2+0n4DNf$L4SDA@@iMOC;(bU8q(aEl8n@q~&?YKvQZg{Dx_O3F=ub)on;0zBK|pKa}QND-ygAhSMz zf9qti4~OK7idvvlh1&+y(;sRMqyz&i4UwYX!i?PePTmP!uY0%B`^ma@cpLom{XEA7 zB3s9&xLA~FAy-|jP1DB_x`@%s!RSS%3e1e;J6)_r+rB969Ts0dI#AMf4G=+yyCQzW z9ptP(N8>DkflzWQ0CjM?WuJq&j{{XLV#=6(O%d|> z*F2H$B9=D9h!|-ugRU0v#q(Jk>zciSaUSDa=d;$$86u87hTjf!vSg3=*6|#_G#^|! z{0$zufOQy}Y$P9{kU+GhXwa-$tdY3AE^)U-la0i6Mr33n1)2@BDl3U96n7^62goX4 zxPY}WjmHJ<_{rjj@RQ$$O5ofUnvB(=fFZFK1%8xcyajklB{a+$ewSc@+g_Xh*)2@K z?jqbq^5i$uKAmu@rZhVYEq(Kguy+DBB770p;gd=cQt&V~tm8aV;e*8SCd+*@vE7B} zJ6RG2%m(4s5wy>+4AKWuZGs`r`SgwZ4!YJQ`<%auUHj4_*lA`6EwS$of397ETp3`=7H0gd)PZ)@n#v zEMS`J`$)Ccer#!c9P9m9&)6^-Uk2d|_F1EYWzF~(@34rL*B23M$*x4=-5|Z0$S}Sx zgJYLBLw6&?FJ}PNZ1T>hmN;-vr~5Dx=$>Cpg6LCLCe4So;SnV3#`ZUu9AIZows&r{ znnow-Cg&E;4pnDZJeHR{mIcbUB}si{*N0s&IQxwF5YmVdD2tJFkQ$6Pnra92th#g2 zWq6E&)a_~X1nI#jeONTssE>d^>}SPsv!50SEe-VqCz4p1@khiw zvSBj<{8(TR1OaW&Lje*f2|L}M9C}WTrH#MvD8OrW>|JyVjg@@n#>n{ZQll zrkn3em-zNYEZp)WhMw6I?~%v7)%m9IpyNy9L=DeS4M4w|MZ#q@;W?{TF%LS;53gh`!@AaHs{PdB zH2E}|Ij$TR)%=CUwfZul67TgVy|0}R*^VLEK*zP(`Au56U?^kgW!KpdfRIMp$Xy5N zkzgBXDb1yc%t|UQER|zw8mTn3C5FZC{tDI*nFsr3DM=%!jObu3>}j=0*L)P$6-j`f z`cLGB#X`}&z`frIxbL0fQ5+{)9XrLdIdyAz026FbYvyHBnh^YJ?jK#Nk9zo3K-F?#b zrRL(iYfow!rZZa49jINDu2$3Tz#tSXvKUyb|UJ4pQN_QHDpv~ zz_TXmDBhz6V2KiukytbJ*lOI|vzSdbC-32ZEoMoIKV#`kO2bZwq;D-05+D`CA zOIY8w+r9&)s9l3}ofje%@(6&pGO$|%FjRiW^(8FUVS_n}j1mQJF+PZp1{#{mwLpT=JU%^!PsDVZYrMe0 zV5)6$Y)GOy8+S~5y`b<?W*6>=g0V{ zf3pFJM|ajwefn4}lthI3NW2p~xN3?d$MP5eRGh^B{VE#}`0i2k5BE3Kx`zTCVW^Dq z-Ht}S926UNtrQ2C!>5y*mf4|W<1qK zKtLC&8Q0WdNjTRc-G=Mi_u&ew{gr`ORobN-Qiu0T8aEe25e)5&9JbUV9fPT+jm5P^ zi(bUs1Wl!?K{%jT%=QAQC2$vH#X5k~fdBOh%N*41C|33iD{WyXK~ir~m=Sd*9Zg$= zZmxBn|K3^jqlB^;ROjuSKII6Heu?$TNtE!ZcJlHL;`r43On?Od(K+}OY@g9}aP|jP z8{#mqxPeI#q6v=7>4A-;K!hzNL$bGrA(B_wl&^USUYEh^_|Gq4-uUPafJcXIlRF>c z0oD0@+**J7)|`?w%R69mnrV?yA$GIUG6^mvpe)AF;+~`~8OIcNHDt7!o#dN7Eg?NI z(hmWX{)2+m5WtE%)TkOY0PXRT<;)s>Y__m5?;gV1UM+d+mk#mO%h^K?6IQ>89vXNx zPI;Qeu8!Q}#Sw@CG%y=Ql|v-)t*8}TmJ>`1U1$fc7eqGH;8GG?=5mmxuSipE5}j_m zAKJ*{EUf3ua1X+g<0Rx)g$YBa^Et%RI3+t;KZ5B~N#CboUD8xNNVlR@@g73ve2`v^ zs0y^bDbQGf9Z7nXMgwcS!-4@9HLYFEGnP;Hg`qj$HRQPewk%N4WMHOM0-S70?JT z3VISRj;gU?JCB$ZxW>Ro1L`F2&e2%Gh8GcYK`m`UOHP|57@a-IA6kVYG^gQ&dHNC) z!Dp^woq~EI$4zlnvg{6v;G0&l2U2%a@Qq+%iy|B-YP!|u0nwYIYE&0&`~>0$q_Df8 zK?=)%<6-MrTH;c&e}EpWd}35-P9TQuo1#d)0(@gExgwR!PFo6g+j|}f=cVgeoTIc2 z;RwBnFWM@$umnrgHRnz`%|biXo4(rr1Dq8IEq7}_uDja~mjjIoaVXldHb7%oVWYFd zhyih#2Lge2h>8(Xsn=RO(ddVUV1_y-aJM6iejJMB2~LQj8DHvF@`umFW5N+V6F*D& z@c*)2=I&o{<-hFV+;hUs9Q%LFHnLo!BT5cZCNeD}((i;Pcw zmvwJ^=2a-H+xXNlldpdlM&pM_K(DQ6+lYXpctnzfmZ82Vs}vbfbsJsesG!}3Ik_;a7rj%)8mmGG-Bv2{ZthocEy$;2Zo2=UBw!k*Ou@` z|6vo%7jdWWf7lT7o(+8Oe^}>&Ibuymc8?+xOwhA$-SyfYA(wG#sh|cB`ta7cDMU<^ zmoFb0f)?%G}8@iIzuT7rU$Tzjj8z>csp^L zO<*_q9QLw z)BHfTWupmku(BR~)sP)W;YL)7B`nz@A?+bUwZ=k zB=NP(`05m2m&&gH!t@loRH-!r(1+>-BmY9me;HCLM|JPR_~O>+XKfit__E%CP5Gg>SmVsmFCjE*J5@=N zY}RWPqI!ZrM5n}S2bY3oNe{S}igqd6oM8zFIRZ6OkcoQ*Z@LCctSZU?b%vw=cXTXe zJCzXCZc^Q^&@&w3JArNz!8Uca6$b<(6>yD(t{6|kM|~bj%ZjH$M@CR1@IR36 z!KQ$wfgxei_5`nqbF8pseu$|zs-V5kdH84bEtDrL0k%PdI8~iGF1iKP=owN2F(g8` z_?b1ZM_L11z@8%lqn$egz2(tV0W}8#e+-)#jd0#-G-RzeOjN1%!D6EV>aBBUKp9q* zgt>wE7vxs3w6TbCe3`OCcTg?BgD;zdlEF7f)}|2vcHqL;GH8?CgCNS#J{_Mp z-sfhr4=T@!@KXaoU}@;2P!#yhp;l>h;eUrkfMHPSiXik>d#%yk8V8iG(7?7(LSqUA zn#a#N1VUZEb&>dy+deYj0kD!~q&bBam6BGlghAy_j5f)I9Wq7hKDEqYW z8*bqcL53rz zV-~_#zxo$z6TcSrqt9es3ex~JWKg9v>xJ!} ze@$x|frz?RWUB}19d`2#t65ZVLA_Ed(XOZ~wtcn4lmc|=yU~O9`Auk5YH?5`K4cnt#A?Q9tHc?^ko3#7Wt7f8rq3V4el(zUA{^2^1Z_x{4(bm|}Acj&_3U?p`_!$24+7hHlXoj!f{gQgUy0|t52T`_T zaX7b+T=h3l2qpc^iO_4V?p`~Uz;G;TARW_iI|_`N6=N@_m&xSwFDsjjjm=91r3$dCg7F= zXu-UM{pgUeuRYF7tN7@TSxlotlZ3O_@g>LrEMQ_Hd=Yq#DSts6IqYZW*G7UL7Y9i@Zx+cfADH>Rn>B&`z2 zs(cIcf8vOPq3CiQU$@4qz6W3$mo9Cj*S3Zgc5WL+7EM#H^sPklLHZ%25qp)r!Eb%Y zBD>!HBt@GM12P{+$(Unq1_`|N zIX=_eSkwHNch*@TyM98uNG?FkG475E1{TKHJ9(Uk>bOOV!A&So!Zv*jst^|sz0m|6 z*!Be~ToGGB6#)C%AaOJ;DxiHTV{pwQ<=!2F_LfZ}5Jajw>T|y0eb&$M8?MlXuy&y6 zWDMNX5It0rmv0g<-rb0nh{z`4Vif&@GPH(fP>Zc(s|#5X1pg`$%S-0di|(NeLHZ?1 z3dm9OgEfCZS&?l}86sHdJJ zzNTb~07syc!UQz~Q`%DGCiXAEFQvBiI0u01i5fi1`{PN@B6CEv?QzD=;HE8bQ?A76 zvHJI)2{>rB7Zw643DUa(4CgJHYL1mx>>{$1x9kU37wXZMK^$2U=|R0QCJD%FqRa$` zydpE!A-iZ54|pk1)3CxsqbIwL8cC^Qxfe;3<;4MH_B{slVObZ0gX>fB5LptOGDEVD z{3sa4nOz)3gbllsW!D@k4=7UXA(AJ9NFvYPmQYuD8U}D3VL*)T>50oEvNBD&|7ZM% zEvyq;LS+$M5C5av$wNNHWiP)zO?OEFTkbcv!tll(CLmhKljV>nLy)D>+sHy0#%<-r zpR!0PUc?1cNaF)r`RY$us5yQy-|{KT9(VI2a@o=>!Y+s|A8unMI~ceYT0q%Ov9S7Q zp9)q(r*J^Hv&KZY%F{Q1k*SdAeVO0s##o*X)?Y>{wSDKV7#B#7oEd!E78X7@q6dbn z5LML{0`^d1I7*Z?pfM@NQ^{5_cadGEw;(6^Q6LOj{l{=bRb&Vmr0?9q?`&iplFu1K zV*|W7nm2u7(F?pod*XxSi=iCqA;%{1zwWo zl3*J5ZQ#@6oJmYvZ@#2Z;pb3T914`GML3$Gk$aobXpkQDiD=vAajqv7>J{7|#jzyo zhoUIPo#LYlw0ZEB=`WHik_ME{`)NsluRM+3dMqNENb!2I78Dvidy@q2N(w?!Zgo1W zh}ffDKRe9mfS5snQVXkOYdd4 zxT&>NB$MBe|MUTCVh#-BS3Y0`jStcE_W!Z=Ch#>L-~YJ#B;+A^mU{&uiy(+3_N9p= z1hJG@T6+^qOI2%W5T&&wTw7eXrNPl!sy^CkgD&W!V&9e0qG+w%^tobRLy-Ub%yUE9 z&!^wt@B9D!yk2sjnK?6a=FFKhXU?3NVVOIlF7^CesTRZblemAF;g(vcMPdUU|_P@XS z;rCs_e)wg7pv;X*tjePWD-*sT+x&DA?b)adt;F)q4ZXs=c zB!wa}Yb)>LmeMT4^g$R55-BGSN_Jscb1<^|k|*ysA@$%}S#R;>iG>f!m3bC6EE8V>_j7RwAF9U)-7^ zthV;e;2{6oH-pUv{LgcdWey(}M*s8XxM=&l0I=b0PGKA4LbJG(S8ep;X517ptTy>< zQ6g*HxMSfD{^#@W&}O~3$nJK+1R1`Ox@=MEXLcuMQlCTRc$Vx2>6XlAo6xKnQL{kY zEcd7Yr>>fyG8VppTzD}hqJ~#0*#PE99Fj2_!ec!P5VI6bco5f6F%WkkQYc+px zTQJbwd~yfeTwso(hg+1gncNKMPvx>E!`o!qFBTYX*`JPE_Px(8@MQ|VT!7Yg2X_?& zwfRLE(Fy!uW?LM){zjDFUfw%Xup$an(77R|CkpRO;lo8-4-Q0eDE>yF_`PXrIodYWVfy5n#rLd`;uy*;WJI@v`vW)d|?4oyxg~-_-gUegv+&`W^Yp> zDkftEIR{OgegJAW>JGwHmPp&ZP3aV)__9{P2xWYn)z)Ei^Lft=o4G-F75E$2xY>jd zcd=R8zA<~ug6fmok~Kc$jMv3wz!>R%en_g3>Qz4nC0HR#a9FT{nQ<9;V>H` zY09qO_Lk$VmL$QUdznWu({wW(V}yZ@S)e_RW}&5#I6eVZLARmlF`GuCrGS>r$k9M4 zc*YX6*;)^Qm6P}4DhqxVN~{Kbcj3~u)o)SbUFeHHPTjXG;^HO7Ve=S=;Jq|rm(ohA z_a}X^OBod+1^exZ;C2NHi zQl0%u9ou;7zF(=P>>mkSZ*r}Wm1Nu7ot#UDVWkrSvFK$`r{x?qWJ*%u6z4rJv9$Cz=$1sgYDVmWu>{a!S&!U_8HfD+P( z8_pL(Cl#9;??Ru#IU3|Ej+q~Al><^G?akUm_YNqLc*8LKTct|0b(sf`@+1%TVc{Hzwz$sO# zXZDZ1do{e<-8`Ai>^pNS*$yi4sx?thKY#|989!0SgLpA*Sue^us8quNt`!HB1gUf` zT{x&z$vip@lFmB+QM}R1O*X$h_n4&-)-+q$TFKTk=zTsz`I4LzIFn={mai9s(1wpB zYXU*24WYmDCvQlbX*m4F6H5%UR{H>aPOl;gD9szln`!bPrD6qHTpx&5CugJ!GAEfm zd(o$d;HuNP2K{hIshT?M=@?5A3OAe_?walJY?*f+onQPwQ4_NiPmtd8@<895YlT+= zS#FM*bqnd-E`G(j%{1!toieDgn5W>3=)pqB1#bYP^QvSD%sB7@;4=dsa|&lm*W-I( zZ9R^D`3}#b{Y?5{rG5(kq1R59 ztWCQPZB%qw38PreBar)9co_PK(k!S$2TR0capCKQzXc!c-9<}|D0T4!;kQSWmF2N{ zk7^UR-TauQHocuMP5B-N6J|`NRo^Q)(v(93 zdi|&}RO;_XKOI#%*-WZ=OsR!yqTqHC;CfBo1j8ma`$L=sWwmxYxzOykn50KH8Z!NE zMk9!-7y+>nJj%0Z0xMV9J*Jm(J}9FZ;~L=>PR%%sJ3Hd`Pd1Sr!zEOs zm%PE!Z201)DS}0S;4fuLRWB8X0g{ZxwV+J#(s~ZJ3+6+dKC)9x4>_1VIR>MEeJO1@ zrX<>iP~kBprrvZ+v0|~DeGUmtLQ++K?(}HbkBWtlP z$`{lnnR^^oFTPI8k1G+5IPT0RmxU*pxN73WahS2%+(mo_+*pq8xacd`0yAzOZT?PA z9i+IO&p+iPt{7wM6HQp2lR>vqo)_4t(>pn?C-^>ti}Et#+^2$E;5)iRCZJmb+0X@j zvV%}HsN0}eXn0zq5CHhlXFozFU3p06k4l7c>JEwqtwF!%lBx0urEa+tzQR5|#S9xj z-A*W>Ek2(oW~>z9kOxd*sl~pKxp5H0x%Gq?-}{j<5dD}00u6M@uBi{v`E~aDOvUmm z_k>cdW&|2*-H**zxQJ2p{?qo0k+k#{-8i9CaIlS4n65)0b#xv|6m(Llo7v}Y9rXzg zWB~I>RM`Y){`bF$WfQomR7QVhD8wc~vo%LOLTSa4AaDp!=0v_<4g-7b-%$AdCT0Un zy?}?2V+f$FJCxbcDU^G~EdP=y0gjYY*|y`U{E)kH_XPUoq!K!)&n=(?waPo^z$R42 zEQk9ZAl$uI6lL&9=b5(wmM&vqu5D{y%blF`$nCp>I{}WRHuL@~Ph@F!JNP)rV6Kg* z3r?z@Gk595Q%Vb)Ld#DnVYV-6+bLy|H1|(x@srXiIHm-JSi~{LXpY&*zmQe}K&`9hAGHv?Gn3GXM{%*cK+s3*d z*x2o~g9`;dmiBAff2S>Hl=!+bl4IdC5HM@%Zf<=~4}sY$Y{?ljalwZp5-v$%!fU_lTe?GnbyOY-o4%KFW|Bf*KRhM@gN zh~V8|&fv{&PUKEv0nja(hFwrL_MZw}*PXXxnW%m!E3wvdVqh$m!Lj_FUUKUis5m)$ zXT$AgTu-s+-2+5pah!}50W6{2&I>$F5yxGK<%cjPcAiR8e!--5ZVzq$Md>fCokHQi zLTgRjLofac%2gRo>wi^JY%9t3n^K|S{)%jENhme8tSjBu9hmJ7T)0=t02>cqB4f(YU83Z$ww~tfS&miFA&xJfL{4i z36E+!(MvkMtMxH<)r1txng+~V8k(KNbj1oFYZiU^Cr%tfD1QH^5)+y9H@>)j0;83u zsljFi92^oF{Xp}ro`khilghij&}Q_nLePoiKIWR9G|E(J_TTt;`hlHI<6CkBvi=jEpZLGY>1L&`Um+HH=r{LedS z^`n;)&LHFofG8T0-L8peH48;%o|K4zrFr^*FdtJ&OP&_79Vodzy-htmN>#^IE~40K zj15Ei7n%Gwnmg~nTKe3hg!_!}dq77$N*%|dztQK$aZ)ZRQSouF@tE{1E5|pl z%y-RYqZ-I;U2xI>c*F=#yvTi7oWlR$tcWjHdNPf^q}=8`w4wP*Scio}SQ!{w1Gfod z+;(_Hgeth+2!}4zlW(zuy;W>sWE^Q|sUQ#_JZCj951v5>JrJMiXXtP~77kU0knd%@ z75>sR8h%;n^88mFirMcv#yaK`AjSsojuSAeSvTk5{7$wQlnq>V^VjYWcPJkV@$4Pe zcBSiic4Y~Id<_(HX}}ewPA~H*S=e@D8oWW662W7;0p`+EgMb-xQH+_`%@VwB=Od=P zB_jAe5SjC7XDvSB6=_a4a$QjdNYDRCmr;kDI)q8=znDU=Vu{$SJ;h$daD`1{+*Kvg zC$!XkT5(l*M%vYqPG7~Qb2@?|tr zXVK1U7+qC9r`y+Xeq#A!3cIc}3GUcJ;LP2~D;M8QW4KI^?T2S+#C5#c+nqPay(O%_ zt|a?Ki~~Ji??6S@m5?eO&}UaLuj8&{*Bd%4;kXw&IU>;2z5_MAp~SSwtBolGo-bp6 z1mNQ~+(Q|56vxJ`P2*6N*%#dgz6!?-v} z)aq{Qlij`pkcInf#+$rTPX0HQu+$EsOx^--FW&!U!3P1zfJ~qQ^Jp#Xz809l77CTv zpo3at*ajr<@QiBz06gc7+U3<^g?(b$O{KQH=S9Y5>_S?1Q>k8Y=68a3nxMp#{`iDG zlHE0kk{0+^Sa?g(q!9+$Zz)p}KI<%mG_)?PF){nWTa#Z`GaZGza>}UZc1BJX_aim& za!YJ6w}juI!?%1ZKczNN%T1iA=Hx}!vGN|p%Qft}(u=p1iV=St z;=)0Y24mmzZXH>y_@wae*J<%>rBXvqH|2 z`O#o0wsyptJRr4#`nv2l&0lcx3WMsq2KN((Jv|-X0WMj z|6mBuPg7rx}O-J)?J2*FnbYo29`B-Cm$`ca@N8t$#s}9Av|aMbQqh--qXd&Efd>1e(LM70L2g7qedvAVaS4C_zCBuh{ErFuzqR=MS8vz)Jzj^i} zAF7qJ10&qdLtY1Av(Hg#R-n|3tdPc>zGp71#66Q;)~SO?ZMuZ+v)0%J-19h7>ny`>-*mFn@Y)`J0IQ>v=&-JJfO&$bDZ4Q-5bNdXt;x(>M2(Hq!Oq z=<$85(a%%W2WaoR?I_^^`0r2y%6fns?S<7Yi51=mAk8uclRmzJgduOw0}RJmQ>C_Rd$FAJ6C(vDcVQm9m~nFgwJ<~<)+(+EB{S)Z|j>Ij!R zLrosy>Zsi%8a>0Lp%0a)n&FJHmk?b{aLf;4b=0Rs^fM+I50&aM)SEk`{Twm>u6J!@ z)nmH%adB0(`h$QiM&Pd2XLraB;o)?};6&8A3m- zgr@O&mtPx?{f3>=)=#ky11K?DYG^H#-)u3|{!P zfJY~8%rlS7SWsULb!^9AMwl=k?#inzo&0(Y9rh4blIjh!A~_w zEiWxS_IAJh@gGe99 z=?ks2u@@QAe8gu5(Fmlr=2X@J3e5I9#q96xH*3!kFRM_1kLn-&zQr9piwh*o!N4GY z^^m#P#*0M(k=a7Hg`0=gQ)?f!Nyp#8=$@XiG0g?>Ud0P4o@?kH(fy2Uy37{DbVO-i zXR!-3FJoUsFhSC$twrw?KUq2QEN%Azg^|} z!*K)ol>3xjTCGiCrB#O#G8HtkcKSwbpv2N@lS-j8Y^;H&d8WdV4c_L$2D|qUnpIkD zDSz69Yv}8wBc;`9(q^KYrPTyIY(3T;Oek>|V}lyhqKw+R3Uw6p=dG(HTQTnTc`GVf zN1vBb!=&>Y=|~y%dB54H&^$5Li1bsN+T`*nT*Iy`dRbO`1={{Bz=N@9MJ0E)7+h{) zZr@u#M`X2m&>&Y~QT}&xXDyrtY9R&EHpbk#uYjtRRbTBfI>)jhpzE^tyDFJSaSj}9 z;jwiEapsC&&}(&|Dv3emb{=FN@WOr!SPz`;(7pS;LZ#sqbM9<9R~A^O&!)#^)k-0$ z9T`vmOfdpiV%0SsrKfY*TYjd7<<#mSWz&Vg0&0kSh^>q1S6sc)v-h#ljb1OO_6_m< zn$?G~r+D?`cAoJ{DYlV)wvB!-r$*H5QAG@f4xnM>b|7a;L^xcK_~OTOG?+I5&1w~? zuD=@NN770~3Sf(Qq}M>r}m z9^a^#2cbD~D}@KBEdtke0#SCLhy>IX&c&RGrO^Q@-hyaM8v@j5=}cStH9)N)`JE>} zMXlAe(ih0Vu&nR!ct%q?;iw(H*|r_-d7mw_5FD;*w zy%E(_)v8s}$D{Rd3j!4@EO^Yfb6Rzq<7tShHj-}FruS8~YvVSp0q30cAsXQ&#k{-{ z$X|fA<#s;cZt^CN&Z7`bO_K|fnHg5SNm&|X;alD4wx(9ElG5jfP=J7JMs`3176a^_ z=WF(#Ney&R?S2#LsjEXOx3aM!h(3)O`x#*Iq>5mf7h2G9U9Fwau!U%EEJi^iEMaT8 z%4DM};+t5pT%y-9&!L?B^ zJNh|0l5Y5x4a&sqh$itH7$IOaW(;7;#jr{XYd;s)M&#m)m-D~k3oP2k!pPx5zF9q- z5B$gVhJS=}Eo%!7=L0{tb0t3AIfTDYOxBG{6zm&;f-w1AF@Q_CJ!lZuvHTRRb*R-^ zxl(5NX7}>V?!sq9+v%=SrvDg_a58S)5pew)!B3^VXzt$jDK=L-cv=GJE`U4*JV@xe zL#-fpYQ;1x97{@hwXSsYV@fEm)(E=-zGixjtuOA_So%I^}oW*2^#QR10A6R>N8^3_xjalYZ(0gD0heNPt?bY2Jmc*3@kEJW+)#n;q z{iwkE)cdrEEN=K3;id~Z!=k+t+cH8Yz=nWGELELG2C7ZfbcptwR1By z0hF-dFaf2ZtWxG|=sk!N;&r}wK7l(B62}F-rr}ZZh56K^g4)cn&>HjBc!xZC{s>L1 zpjHka7mxhBqHpcHueH$7kUy;$n>R<%h6?Hn($de!UQvyc27f^*71cS?${O@DejB$7 z166uj2Wr|rIZy*XhM0c1e44kr(6`XxS~LZv&Fq`zhC}pTCAFiY@;+#brZ{aCjrEwB zy_fDFUfQykS_P?XrH@C_tRRf}>Mq(Gq=wl>)9E0!e)!HKVu9SC7{8m(2<+2}eRL?Q zvKrpCdamfJC$0F3p;$-l`>D6FUShvzWsfZ`?mfr-K*_yW^-z z74ycIkV+N?so2H zv@@Qf{f0MJF>tNn7&xm?0-HP5vn2#A*YRQjUpH;mjblzeJA$Hv)uzF7aQ+t)VJy>< zNfR>y9!*Tw?%&abV6{&3*eRCWK{4VeL2O@yF}ak=660exD__YZNhNOOcShC*u!Bp%tUV%U(tm8eFSBv?fHY5|sT6qYyV73d72X!EB|0zUgwx zbUs9FXWLG-Le+NC_J%YvRITE_3a2uiro-*}@e9fcRU4Kw+oDfU+Q5c%I8?1D4LwU2 zLscwa8&g!6+6|YOO$bw~JmUw${w5qqXLqG=&mo8{w{tu9GTM>X2!688256TjRwNwu zCah>ghr-k-`Guy8VY%1nahTdqN^d~@s;UvdY-&~2X*)z^!qv`F=rQUUt`77e`95t7 zSD%w!IZFQ3)FcTyP3LNAJD<3+_i14@b%vBagTkt-9m)x@hw2~aQF?VXL0X%oEiTT4cS-@I|Ak> zxZ6K_ujhL(*w%7*&A@|8VT#Nf(Iqn8e+|pBJzmjyus%0#!eBvuxb_#p^9+V=aO(w7 z#6>G3)IoKcqTYDt?FyLjs+y4qWQ#yCHxw^1!%i3tYN~^6RW5*nTHC!ymwB*ZY7;ZJ z?NR})t)*5D`~&H((fX~AGx|^YBMT62=Nvj+OReb_gEw4U>-LjhZFQe?t`>b?TMY-P zZ`4*}ZQUp;QjHmK*(@r;vri$Kc(@9ZuQ)tC1Ko#l8L@>u5wjt4b8Er7YXS2p?q5228*}lXRd~23%MLCDS!0gA64-Cz< zwdjjFYOTP>=?Ju%Dz?-fj#@Q%dkJt*8BQjpMB~h;W)u;nz9n6+K+B_m zO2Y^`8>L3bxu2n4Ct}M+tAhhG5%PQh?48>~_(DwG9Pt@ViB?0TZ4vZAv|6#|Y52*3 z47z!EfLIw|7keq#iF;NgVc#MG56W?tuiv7AXmDmo6KWKL83UEP8KYJWxDK}PbU`KN zYqe=*jM`X!vo`ZooisWhgVj*lS(56iJ$>$!zfUjJRU<<_t0ZOz_z^HQmmpLurou@?dJc2_)h=|sE=2U|rB{ngzc~d(?ip;GU|q$T(jUjE+BFe|rFK1B z&Ta^2x9j6__7ERwc#uqd40Jiu#K&NlbD;Pb>T(ViAH!YFq2eRmPli>P~F&@upIPDY6L z^u&{!5!~#w3Lt{D!u)bJdTBkzHkVjI_(k*-*NoR@U*?i0iKO)cy#&!cV4m9 z$|FK+dy@5dsH5gjI7y2lc%^T;1F;R#Ky4tQmyb748%uxGqOuL4t|#SCy@qN?u@i>ZnixN{L4Ozvew{0U``eZzR`*X25c?NPRX??M)Lg)@P$r$(R}t?T4u{~IGYgpAV^G`^TiIm5aLr|2rHzf$ z>W-aoac1(G5U3o#Gm9=aQtLGBJr5R;Hv|;$5;OQ8 z_WRVau{x$kPB@Q|Ha&&^HNT?}3H_HbYOoJt91Jx11YKyXR;$&i3~7IX&V_R5?dR#OX6jpVng|6vZ#-nOUd+EG5OiZa{Kq_$94hvykzwpBx9 z*;$688^_a+oz)m=^=|U%qBfC2c2ZmyHB{@f0GBPCD!Kq`$9!k{0(!ZNI!{`%g9^H+ zzjj};1vO$Jm9|yX?CAz+20NFtI6h&!70>!X$@n?jtoU#dFP0+FzKq4`SgP9%;$rm} z>eo#@Ce2wujh<5nS6)BnVbM)Z&)JP#9jkQ+%?S-yNS{BaMoIw-jh~)V@wiiTDN#xj zs@p?-UD};)EbGBWph=H!qVT$n>2yyuN($LWe!bK&-Ip8y7Pz%3N5@o;`w{ck2tktb zBpxR&8NZNHKFvRYZP?WeJ? zs6~|*<=@0KxxNL_i4%C-+b_%zyKDz^^q{@53(|Uk_D%CI2Nqcw^2Sp*^pu z3j*(&oZ;h8p|#9s|1;NqW8^UPLm$+kzpnPG^zrXEy%ZKToJJ6QSlO8LIW!JTz{MT2Icsz_F|5fb74V&mRHqoP_KA0hol#{DBSg z%{Ps8nQD(R^0SAz$orC^%}^_rE*pJ-gQp*rrFt&4VU>qPsG_wv)0vGoi((!kyP)+$ z<4u?Py-!)cJq&N$FH6tAqfV1fY^780sB7edyEuA6f#II3CfTYxcXF`ty|SgyI(E(% zPr*RqBtwLCz!+Xg*XDtv=MYtXSAA37x`W|I-lg~7Rh!EbMJVPjoq1P%MM_y{w9Qcy zedWWO8EEninoStNgBQ|9QeCnlVz*qUPK(sugO)DB49{ZLIfuV^iZo}iLr1T{*iCzq z`010xS4CnUw=?s-;+!M-OXN%ui9_Aa)lU*#?-`}vQyrz{xUU%-&n2q5OpS{j9)7nd zyRC124KLrqy+qu(3=&3*6jxh_DQ#K;rikhAWSSUy7xUZ15M%B#HOl6g2v166_iXh_ zkcTylLm#L+%E-Ica4lngH5PoVrk9aBeZs-Q)1<6Xr+`b|S)+bjMh;%iu?LS+;(B!% zV$ZBs&-mc?n~kckkDRlJQ`>w;d-Bv;Qa}Z|lBaHzbBSY94;gDVtE(ira6Sif4;cNn zaj?_794y>R%1*U~l+c(u?^G*EDa~lePW4S`Nn`qDr+P;^G21w`OKn?LZakC0f6Jqq z->F%0?hH|M99Io8#&FcTfuw5~#vqm86u`wDzz%QA%h@F-Nci zvLul@9D$A(kW535U}=}u!uaBdddEl3%@U<iaf1F@u9wRvEz;)LJ%K z8zX=}F`oTJO|!|lqd1uQv9ab?byjIPcsK_SE~i8j1PFMIUNY6R;CF{{Z0qG1D&vBp zNBWLU@><|NdX;`Mu~cmRD#duzrnRrV#(*Du0Kj(aVA0H-bEZG2zym*I0DoZMFBw3y zJgQrc7r^<;DD)EQ3VE4YUs8Wdihh-gIK8yEi02_Y269eFiihHZCB=&z6XePXX9=EU z^<1|QNSA@1yqvGvq? zIk-Cq56(0aZCb34e7Y+KUDIfiuQpVoXN^C7HK3K+g`@qQ^r*BJ6O=FrY}YE+Hn5xb+;dgCsQz3$CHnrcECU3Wh>f=#+~%jo(mj4 z!J8qbI0c{yvXXwPu; z#R}T%rRBm{j?NuH{erdn9Q}5%7U3f=Ys%4GUZYK6T1PoWgdV<10adjaX~_a=UR8U} zF%kO$th9(VrE89J{`<7Fs`jq5c{Vi+*Q!aY7f_FIt+$l+4y_4C;UUSL#gkhVNmqA@rCmkq!|W2^VG01zv;TFqZSol;U`u7D!)$@V3+=o^@VV-vw!Z{HF8hwCjc5*fxy+LG*lkQd1!sPfyOo#j-Mrd`d zmCY7G18Qi&4I?e(!s=dZR(dM)#*@n#Q!*Y#01x}YBEA9T*3eq0tD#?^1wyGxSxon8 zXb}>ALnE|!>CpT1LWI^KsEM}-tR~np5#qT4d|WxPv?)RhmM7F_bfO2-*$AzX6!4y5 zuc`IGkf_Vii(jGFKJk;79w5#in3$1 z2>D;ZTtoM6v>{fDs=TzqO?VRUx_TztNOxQi2iay;xJd=ET35NO0RE;cb&b=SH}(N= z+&DS&qPQS0GQzn>tP(E=-sESSL->SLNL+j0%&(D-xz;=uc#}5AX}#nYRk%(p>Z>%@ zV&%t`IkdJ5z0h16BRfT?aTofrxwc9^7Q|`J&NMw<8!vYkA)n4vIzj9A($z|wwk!pL z4h9^zYqN2;$TgR3z1ihlS^VqHiOB=ob@NT##g^9JVO|Y{?J>w)C$bLWtgM*jh^#Y2 zR?t-tnDf%^1g*OqCxAVjjH-#+HXnI(d9Jp42jgOrHo`}Kq;YUfGNmSKQO&ua5lzUCw+k%1G?5RhGe!y@zPw zrRASYj?NA>GKXmkZT9#-IhY@eDqzWm)y}9jLaSrLsOUCQ`%?1%!|-`s+g@6BpJ%wl zKsuPAMKykS1d5R>;4s<*a(jss^CN;CA_NN$wRm-jhslE(Z}_hiIaY(h@H=%FtBsX& z&T(;V%F~{)T2j@3i+790)(`?Rdt5|z`=R;ur#!fdBE}}U*C9*98(OjyaF||uL#rwU zTr^y7Xi+}$;-9&UPMWdhO>L5oT=66a_xe-oNm`Ws;Z^Q2Yg%Lt`>HW%k|vjx4}Ql` z6C`ra(7H%-78_@0Xr^CT*B*|Je<0K0x3yjzU+W$1PanC>4vxQd$Ec8_;Rsalb`BoA zO^Nd%;V&1^u=!eqf53gTvK_B=?i=sV*KD?c%VqBsVLuL2eyMx($pWoG!<0gX3GnPi zFG83;vO*iVPkX1~*tyM-%Ey=kmjs7ANSi6e zIB5MMZIkp+r}X!L$)QTL>^FFT83f?`zP5g1-^yUNI6EYfD)sonE5F@o$A? zS~LDl`9RCI$rIKwShQ)JU9Kf?bd?pFKi02baP;Zljk+tfa39%c4F}i#LOnmhNOrE~ zP~%_d$4|5ovMNGbFHpx-kN`QkoYv+7?OCNQl5c&+p?{sHmp|2NN;g;1oKMl4F(1*< zPqkKZqDZ}Rj)FhaqNF7Xwf{`3?!US!NWpxwIgBzs(?-d|KIKA!&(W37v>wvK>eMDz zYgc78jvs;W`P02dhF-E|d{`Y}{3}~NCA=bv7t?rhDTDwMy+A+@H)uYmYu(vfIV5Dcv@oi zb2~#~D1D<=K|Z*ctDo?_;ohj7!kqOU2Nxfv5u3CH<+^UMwmYVh5s;^qv6UO>jTpVq z2-&Rlg{@`*!@ItvNn5qq(t;c+yG?5+bP4L?d5yPADhm4P={1M=umm)rN*SsWpdpm^Tq#Q=F z?tVJGU0WpWPp7dvwDykg(;pVy()zlNTfd7BrBnDWtum*3c4#N~cgIex^Zx*6#P8Co zK$UZG@wwZn-+t{==~Oz&2ecOa+u?wg8Gb<&-{&x@TKBv4ee#x;2C{JFXVQ&74`2u} zc=dx?S`9BaK#IZB5+W=}fo|TZbmPN=+VRTr>5-yi{za4i(3VRp7gN=X+C^!}V#DuG ztsaKza85qB+(K}QhYaB0p&UxMqs65TPXp1*K%;&czbvu>hVlpN*tq)@ z0t)uB{`>()-vIFeeS7n(90O<3m_hsjmxqS~`6C=L1Nb8X3;BWc{T=Puro(qw9NH=M z2JF2VZQ+^{jBAd9$76)>?g_%ers~egU`T8#nOSMn<*qh3b6G#ew9C6PPemr!N7&fc z_XhI~jtEM9;!wW1Hcu|y&5;5=>~HY%{}H~0fWJELujThBhOhH)6{sS^*1u(F(%X39 zo)(Q2L@&m7g3E9}()vj9upS%?&Ni+TvFwfS&cXbd6l&84NW;@>f%$8GvmX<`QLmh_R*@X^%7N1um#Dmicbbo$OmkE|Uq9yFeLoYf*sw#nRh zcTP$MmS~7XtOw*Tf6TOd z!b^oy&dfHx3e^8qRxWJH1?0X){lau8-7cCJrUy!wXB(e{>1%CrVPlazl=_A1U6V`I zyMa48eA%~6nD%|ytIE7omt*nJlUy?PxQNBE1m+*+7y-MrE?p1T12b2NR2-LJN0%q5 z?~2$U+&fe(cUSdSG%v3^xmJfHf(Z`m2bI#nta6V-Jbg1XufnlCfXMP(d|4K^h-J z&8q7$^3{e+%w6+r!m&}Y^4FllA9@ojZ|7_2TJJtWOb zMq({pw%PrGI`q{S#i-crf?dB?Z9UA^!5CXxZ!XzVu)C?hEXPMNRDORWG)hmBB5&2^ z;J?y@luye3q3jN5|=Sqjh7)E`4OKJH`7{kozP7|Bz zyUU#s*!6YJ8I5fdy|H{OlvAD0)AVNgTsdBZ@}Hy7XY>ziCS!_pl@d>Gbcc=5mD3Fo ztN7GUaz?20vESq%>{=SXJ)_T*Y<*~0bG?c!jb=30ugRx_xKvkXniQ`uc9bY*o+xLa z5tX3NlNt?1dH42;t#6!C)TX~CmbF7Ub{{sVd990ByrW!n7w%{pc01`x3*D3_1ak4w z&;CR4>E7Zq{$ugu|GD^y)VU3c57xQ(gUOVbtoJF2{Y1vzm1TUAtUG+zqY9 z+UxV>LVwPbn?(IO=zRi2lWl@@bLhily^3+VgMLA3Ft;R1I3(f6Eq2XE?A@IjwlWcQ z8$0q=^IgtGl;24w`(ZyWdvb!{+EebF)s&N>KU1gmN#WlciOE7ZLc6!IfW%ZGz{CCy z{_BbV46X|Bt?|XBZ?;OG`VZi1%P=zi{|;XLAHcf^@W;)IOFtw^mv;V0DP8o+a(-zp zZEjWfBLiA=U+<3JaEnh*8srANvK zA6-Y%ghu4<^`FXHZ#?LQ^5||){S_MV0y5;?=M2N@i3}*q(~HZR)E`N?cQ`3EsyONX z3!LPBNv|s}yunHBYSGS@^k;3!6fj5+vYj$&4$`|z@)?0_&IQVPS#NH?fDly92+zyt z>$$F+-|67XdVRUqRW6}SjlYy&dP}%$m2h2@;JE&`5^g`BfLHZ8a&SHuaj+^SzKY4J z#3(BO?N%kZ@=h5GUe%ZQME%aiO&eM2l=Ci7>InS>dGSRq zxKl7~8KI|^FTu<2iB2haU__79uS=C4qL_Po#Yn}LyEYv+OoN+CQKM0MeVZ@6G)m8r zQ-9^M{40sFtPZxug;kbpM2*yMNR!8Fp^hLFwpq0H- zo7S8?e_Xgeh2;~@JY|G9A8V5%M-VWk*=urnvtDjr`nMC^aL8c?UVAlI7Ekhk>nvj0zvL7swVkoEb0#h{+RAoeK+ z-fEl)Bu~_9*ussNiTX*YQUoBp4TV#qHoc~xStM1-)EnAjC?!*WBP5AoED4CV-~w=~ zqhcWelj&ThK29z?#)#y~)GteSm89yI+(S9x^dL)bDuuSBhEw!m(ibgg*%ZB_G`Iy_ znxdyj6TRV_-rp$k+l*dt>YDUh0u6KOeM%w>F4m?uVuW)d>1U@v zIAEH-Ri1H#(P`#ON2lon5=GDS#FZqr?C-T{ZA&vVYSZs9X1UxEE*Gw9;RR(Z`lB1b zv}p|h*lDbCG3Fm_`yVk6en(&)|4s?aSH4q> zxoaT3IJX4mQ|1<9o|{HH=IRmhuw9IKZ~cxm$tex%IJM$tU|Yai+4Mlu%Y)dvp;1u@s9;|BvI z$@3T=SR}h#%&O>@be_Cowdpvl!NFwBm79!Dt*wW<*@Jt@z2k}dr5HXzo4)udd<-Qn z)HlkhI9dgHag!b`{EzK&JsD#E_w8yUz5cbgLHoYq2E}*!e~EYJCBVCr!FU(uld@DF zWT{S;oSPzKCUcJvO_3SFO!A5@XN0j}seXm!k8?TXWelxbu4k4FTgT-b{?m_KDSAuk z-Ko|*nfDb(5Brmrey9&9Ip8~s;vS&thFA?IZmS`QTd4FyS|m0rT3U4|Vu@ zcK#Ie+Ud_Y$#tG4efrn3UKV97GOm8A`}@dCfHL}gIoa0e)8vC6i}Fs3OepW{r}}sw zdihJeftB<^T8oL2Wxyv{y^%$+$pudiJGW2Ub$ZsgY9x1=k(lD^wT#O4+1!MKULnOhseS2b4>>i z{{#KG&cD(BxR?HiEc)-J-?r#e<@^O)&f;%r#8!Q)gh$2eZqr*yTUSx~HY^~=t}?#a zrVp0n#_uxNZ+ofcPUy{x=W(dhUfQx#f6wY2Nhp7fnW8yEjiI}s@5;ra$gu6zeQk0l zH|HwcLCQY;<&u5s$GP%`8q@aa8;Wz~rcA1bF# z=Oq74qC6yx*{4_Zp*N3$I(bt#Y1r4a^r*hCq+(xJba@I>C!B|HMpfp{D)37*vXAM{ zO12(!>_@#5WNg(F`Z{^?Brd1kSM>7UUBfT1AL`Yq^ktQd#D&hu;^Z zuyOvRzD2SPq@_RWFV@9Pb>OR9R`Z2$IL;kxo#b+1B;|Dmpj#dSUOHmekfgJ${S=iizo zB1_aIlj~13Yr=4@D*8h@`=>tC;x)d=!t(xbIRlK|Ce$!lw@MDAZuwXTFCHrJ!*yTz z`cO*`98pT-if6WQ1{txJp$Afjd|jv5YkEI9Z?K@=d;d^PgjEeiUPFeUTgY&FAZKtb z5E;O;Wv=VpeJJi8c(yQ&lXB-3CtbY7NtFxr+Opo4leW95142^hN@G-^-osyZb>`^! zsq|eLdz7?bk#WC_z0f8tYD;%zdu?ezTcc`O`-?tO%rnN+0Q(qOPHo8<{4?lLpuMj2 z(rhE9g8d^ODYq#d3$kZR4VoJLE8DyHNOO~EZHWC7X=Zz)cc{IVENzQ7GHcr5MCD(X zOUQeXI@h)@lUgOwmD=_c=~hdMkF&ods zlk3=parSyXelTYgx$-jT-2{6lV0)r_rcHdtWOhCxd=S zv`5IP6$Nsg=ux7*I%bUU7WPo9^xRoSatnKXZ|S*n=&e@v*xI7l+_@+ZRAaTQgJ%W; zPi72JQ_g()sg=Esx28E%wzWM(j&^WOr`!FdrbPm=CEl8ri_l7|CfpSPoN?XLKh*RE zr{}Dvvh7fl0M1!y)l{f(O}VZAG7GXs;Bt2G&Vn%_lxEF>LV0x#WKr@TXTb;thHT94 zX!q)~&l?jM?foKj2!H=`UEgzh z?s2Nz)gC7c;9O*_vI*wh)4p7pEAB6qof74pDX#2-2>xzW7HNvmW&Himm0job+}jW7 zv+nj-SwQC^@3$T8A%3N}vce{RsjNVh_prFKQoJ;A`aZH+CW}x2{{H96bWYC=q_{q4 znE=j3))%^>uEJ}mYghwX+Q&XBQ%pCNysMc}tXsR5VD1vyM3Q%*X$?VFu4SjlU1`m2 zN#0B`oGFi&4#+eyqT63HIn$5;MQbqkH@x4)vZAu6hk1nDeeE@*L${5u`r3E+JX86` zH8y_^Z@AsMx8wx2y;UVMk!*C|T0 z4`WR0Yj5A={||aJyRW^LwEC(SxBHj=E8H#(0&WwoF>cWj#kkcUV6UXHY9dJOH@OlF zhSYO_z1n|)@Ep^N@K3-0R|uDT4G5=t7-9dgVuZWC{9h4s_^)2vzB%__;TDw++~R*@ z-0~|GCSlzdui_6iTI0`c6o@SOe2q8chGNHB zX155;3*w~4p%WZG_ItN;I&a8%4}UMTpf};_!O{ukGJF%l$FAiQSoKa`E7}OV4yNe+ z^wxNL^=hRM({OwKG4qwvpg;+K@WlvYNa?g?y!|4E)XF#Q%`#o6!|aR(02Lo+t!r-Q zGLDIV5_8_|{EB1hJc-%ncJAYtN>)snDYY`ihWQzel%7Nu3CD^X9Lcw7p?p9VA=&Np z-HAw+!qchmTXz4LAP(<(3Ix}4>~L`;?i?%5d5t5JcGBFp?C(~r_Y=3}oFaOrz{H)X zkSobX>;!vff4G!zqHrm(hge2OYn{svEwIrs$k;N&-W*%8$fmW;3#X!4_I73c4|2A= zqB7Ja+umPJd4NMv&Xk+R`fU3mpYAC)5p;1R`m+fJdjn4@kh69}a#C=OBW`fNS0XhL zsb2ECb2$Zt0SevB_ck@~gg&ItU$<2(yLhkYmclZ$)oqVPzg%)do$yY*q`qzMW}%Xs za+8L^!C+45twRhal>UF%dYra|I^2 z5)#<-@r)~xo+H}n^tRK=-}`Ag#54=*9G(wY;DHuBJQtwQ6)Q8cQ_TFX!Sw8WXqBh8 zapPRKX%a$DyMj$XGsN^UkhaW+)DNPw^X)CAf!`Qm3+ylWCIxO_Cgw@RI{IpD!NAjB z^jJ3`f7FXz74%HK(bC)S<2_V-R4B7uOea4}BB6KdFqLu>k@YkF+IiF^8Xru^* z<*9X~*5?Rrszhd%p&YY?GxCPghrXzeBLE-!*+?9*hPC2m&lW};&VE5})oqt?+C$Aa6GVV;Sv0{b&q>oe{=X^i5xAhJa zSZw!y43#IA^R{K1@h5h-oVS`$81@S-{lxyP)xk2?w;zu{^8zd-VJhcfI#_p7(d;D4M&*-bSi3ie6r8 zuVEWS+5D4Ep=<5cr7f^z@b7!+^y3=*j!mcg{QF!wt>O5(>GZ=|`(QcvBgW<6Pe$VB z_Mz}x{}%^SPZ?{zu)}Ah%?b|QIzbh_vM-YV^&yA4pP&t2+2_jsB9!+dbzWx=j}c9N zVvgo*hgImMBv3k|e6ik^Ea;w_WW2Y|-rL94fo^;a3<{TUskuK;Kf_)hEZ{cmsn*)Y znL*bK`=BSwp1vFHJ0vUQ8cx;nAULdr$258|59^)rpts98k*4GouR^dA`tnH%FMjfP z@w134^#878g|b+LI8z?cb;JIWyhxPP?UC`qM*DWjPXt}vXva2GX{|tdkZn7vTqOYe zP_^yF%Mn)}dhSUIcxTjh2$6L;T;-ts^wDcQDNt&*Ma4*Rpr83_O;w zPhl#;!1FsBcwA{l)m`>r9~gMz_u6}ALbBY({@E44kk;PgI0{o007N zH3=4Z?gKjx|M_AgT}HNmU1Haz3~Xl^4be-8#aUPGn`Gy3{4l5h6ElOk?o06d&ir*= z`Dp$NVfP!2a8$flB3s@8)-gAM$mtzrSl`%bKebB3^h}X8++~FNOG^)jBA-~ z^wj}-ddX#aOVP}9qsh1Svo<+HFpG0MRX$`-lm5)5afj^P$UM=TIm^mC z&C0xQm6f^TG|s$t<3D7c<;^_D$~;$OwtYfhAGLQaTbRXpb2pTs$?^L8mYK#f!&$rS zu!=<|=yRpUCgl0QZ@2%>vHy9y{X!vKZJ{6W)jq^BWJgOquXY+u6yhHd`WR#@#DF!{MG+d7tCT-T{1ZR-`mB8uz#ql)I-rOTUSyqzz}d^ z3|BN`6*anGf7a@D%X<4ZcYDr!!+ilZ9U14dST--AUw*YG*jiH9Z^*kho%6o&(Ldx} z?#;W>%Dc+STc7G(v{#bzMsVI?E2#5Dd;MBsa9E>jgQ#~k@~qM^6Nf-fd2K;o7%MK? zKY(ZKJ2;il3ILW67Yv^J8W)%Pfzi)nUj-MWp&ZOzN=m-H4}{l{e0we5<&AB)U9r$s z$#<^#+j7dyw?}2poP&Xd1Ht+8tP_>NBICg&-hq;Wfzl(Q8(#Vu9?=6sCJjRd)7^8J z?)bvuXYuR8mB@UOERo~xYHv4v8aL|)ND8;_1}M>`;!JJY`v_tQ9O=pv?ZuW=Cg05% zgJ%ek0_#^yxGQfx8kW(-`PgT2eYi!8jk>po_n604zq>;l8_E_kZEVG2Yt%+T*}Tn6 zi#IH`ALkWL!i)~oFeUop74z)C2mRf1>tC72$~UTyJXvsYx4%% z#1l>0+Z)jpl(ovAZB_Cw@1|Zf^@W2R^Y{3K!jp)$xq1j&M~a*gnFJ}spl96+S}LL2q6c~h9zmc z#q+!Ia*0xhTt{|?D z6MbPeo&_PmYzhoLuXC9~J1p)ivpmv4GJZ=bT-?bS;wgeK--yL&ktdm#r~+OHBG(|6 zJn@Ul(6SHp{xIq%UbheQ@vS-ylKsVxuy?(900VTIPv70L4?ud|+x9FUn?`Hz*=x(L zRFQiwoxNudj+_{gG#$^_Y+;Fr8}|9(nlJI4{rwKJsy6*&j)wo;^dbr`uvbP=%?s=~ zl5}k%9eH4{C{O6aWktK`$^(0Fdu&{@lp0&2tXH|LlRK`Vto|I08+QRR>v?>;1BB4Z zz82@vrq$s@rx01CjIM?Dc9MVXw}jXX@_hY>zL=(0kw5OqmGzoUJ0C%JN;aY&+kf_v zjIrb=Il=?up5s){^fINKzh8$2vfY)p--wqSdu*X0U13WQWxv&$1=4KUxp7dkT=n;PfO<$u|^y|Qosgr0+ zImdJq+Q#2;)5m}2PyyM%qdg>jcA1KP$qbb@p89EySj-#?HAge)i$vqF=E$}AwHbmQ zul|_2`8g{3wPMH#Z_rY^<2{u3jKeX@PkPjkc2suMk>7~p)LJ9yW@X0+qzf;wysoE+fh$x9L>3Y8vyMSt~1Re9i$YF z10){$f`~EC)7m3!RU2gef_77_3cytE`_HEcK12Wwq=~ znNf~ld2b|xz0r?WL^+rZ{G-t(>3jz|Uk|B6A~>~TUy|yJX1rG4F+lRW)fP1Q_z^At z4SiINA)j;4~78c%}~97pBoiVSnQBPAv}!u%TQ*I*t_rk4^Ob!}-hH_;I; zcViin42PDDiH@dNTwYCd{Ndws!2cSZXys^({hV^G9nCTa3L%u6#zN>hP#^Lw(0rvS zYvdTIfu2n65m*n*?udgs2<#lLo~1lGqAl$`p5t92-tMXLwEwuAs$5Po?k}>&9HQ{r zJDvvOp0iwjXko_vW=sXU-Q#4N4pXQ9oBmbfl%~%v-(0m zS(SwI#anUt2+p!(IM^k{&+S^h#n{%-an&bO!;PYznecQ#+M{XfP zS7Rxvt0Oi1w2!DU)>~snM7q0O%WN$8uRgje2>el35IBjBb#=s7OaXy;?J194J1t*C{|3+WFJk?Udw!i|l3TG8Vb{H#qIyROLe<=hwQCIA^ef1ufwJe6- zN_C8p$B0mk7`l_{$g=0(74<}0{0zK|8EKAAl9V4r$ND=O$*H$F-Mo%DE+cykxkxpnWM*4qmPC- z;%tZM{18V&+Z?jL;)s!Jh_qwj)b;(_BC)ho&W!Jm%FOmQrrId8-9 z5uBhCJMOLQCDq1^gG{>fm@p|ew$Hqy8HlRNt*x^ho2JzcB<;;qT z#x_Nx#<_vUG+9FnjkyTpOX@h+rlm?~qi9T-YvZW7T`GrR`+`PX+XfobWDTuBkbHwZ?b{jE#e;(dGs^CbG_c zZGC=M$04mHYa65_`3A?+Rnbtb|CQ3>5K$K1qsm1hXU9ZV*>6MB=cD3m$|-F=N^P4~ zQ8_u^#zB+(iyVqUrHeu3OQC^^iLA1}8BJe+P{u%I0U|20Z4goNbvYD8#rQp1{f>>3 zv0VcN6Io%uwHyYDzA-D1C+xb1yb#KXN4V z6d%ov?!GcvcgvNG)Gb0B!Lkn%OR`O{@o2fTxiPQ29g!{#9^p4WW30y(0Y58MK5{=7 zc_+=4A2^ES#VOkVk3R<$78#WtHXU1i&Cb2`Ab z4JGV0(459Dfvx5W+qP@y5!-@gn~8=#NQ70c)$~2v=3Qnt7d6da zYLlwDeTi)w8d0P7U<;OQCXMI=ww=7lZu3m3O)_j5H=7uXFang*r7rj>0c zRrGxdCJ9^8EVCJ_N&c2qx~gdUGLQmoVzQ=~$?eAUNFm*pgPbOlsK;f?p{b)oOkVkh zHIt3Vb_K{*6tKc(tocBhtdSbgjukfj@G{xoR@l5@zWuzM7_fs=!8+zIPqit|(5&so zbl;gYp{3Tzxu|nh{gYS9ozG_vUyYRY{+>Y}wbbf#?>*ORa8(mrZY66Sok7s4Z>ma?*qy=J_<@mnQJ%!sYipt#Lol zk2@#6sdM2k@*AZcY`XEUN{PHeQRttH!W*Ew%KmQmc&)#_f6*oOr+(4jb`{4L{CaL@%2{ub2L$9F6U@o8m$C%en>`68XJ=m%~M(&iT*Q zYyYIA(eN~CYr9Y&TVf+ zr^i$Jk#&CfqoK|`sS@G178o{5Kd``7SAN3 z;IKgJLX{y}4^=^Ie#^07HAf#Y9n*n2Ow_he)itFd6Sa#pPBMF;z04Y0=KnTP8>VWp zd_k-;pMUYv;GHk`<1&{ilL^er34!j)7T@{bU=hbbZMj;2SfxVB0T@!u-WkI=r| z%1Bnsb#5f5CqW5ibDANvOp+qBmo?Uv99m&(Dv!{9MvEi0!L6(-WJ>osf7OxNn;Pr; zvQjI$8mT>i_t*;7gma}A@BKGopCgcov;1X zA?G@iVa;TpyB+a)6eM`RBXUE1=W9iEG$Lw$nYP4hmy>>hHo_t8XZGN0t$1)ZcyNEE z2kUrkm?rKTdvI-9AMFS6+8;G>Kgp!kGxA;SkFDdb%4Cy9e1k%RafLt5Az)mw#{}ZI z=14THS*ShMI^#!H^S6Ax+N?#|i<+z-SS_S+eH7CZ5O3D^GHLOQT+C#NOqxF(%-sAu%PFSuI6fA4RvNh_~dDOg4H(zQ^Q6nKXSyCNp_K zCQY7^DNKGVld5OrGA4^<(%3-ecU!Ib?>Egm&k7NeDOW#s zLVBlad$fv?NhgpE$M`k=sd^~w4$EJcs{K_%xv5%#K3u15Yx4u<^`>c^vDN*r<9xp; zZZch7r?qV|=L+6t5&QF_hy0H!*J*v#A10svD`7HiUH=c~g7t9zH2Jg%oL}er(@A`r znl!0eS53(=Im5M-u}(V{t@_?N?OYfW*K6N|@zr|mM1|}}<2Gm==u$7iDlx7svgzDf z`^ctol>pysBGZu}AZvo#ACmcBAb?-0IP{?8g&lr>=Y}VP@l5d7oKB~QC`?+sL2GZGpmZG^qu#PX z8>1;Hkn{0?gbeK#7Z2HXL;qsYBjyG(+4mXRgm%a8;#BVOeu|EJGQkAOFru^pn zwY!Z~K1=dX=V|Lqpn39;c7UXm ziwCWO<1N3>7J5SaE@Cer=AyQl>g&()mtNGWM`*@-b77dzp!XdGcZ62pD15CJPmYF% z#eC*VUOMwlqw>9@>3tVL)b#GeKJHJUFIM8`oklG23G^&l@ zjqBY}Zh|Xiw-J1S_qyRSy{?VW9XPSAFidsPj?Lk?ZvLjNFdc?hJ7J-*$lHhg5_?%xmal}+pim1W`zyi@)9QW$Z}$>5JhW4 zo#MLLQmZV|92Il7yJ9B$DkcVzd0m7QY-vB~BKY^nYAJ^?Mvm#f38Sl!u7uH&T6+tv zUA8!KKqGPY+b}3u^JX{qjA%nb5@@=&Fr=NgtXLML#F(ZyZq8K9?KuYJ0=nWYysOJ- z!J+yal#30@*A2=Q+WhElLS7@gLR(gg9VUmlz0MGZWqyy|!WNCDaT9hu(w}}AC=4^X zqpqY5{sQ0S$@Le0Q<*F`sm%Xyh~T3Ne7hsscKyaXKDk)m8G@hj*upoy`-ok*GxY|4 z*XY>>y?lG>8#PC^s5iA7CJZ;pGOEmfdzjG3*!UsM87_RR7$Wr_O}DtPOijzGCXLChEmEMp&wXc{En|naz*p3G*ANI@M9LcM$~+ z-%NT}NV1am>iJyA{6^(t{>-mdcL2arMUGk%r3BOorHWzRJ z!yn|2$Pn<7pWcVrdcO+qV-v=zG&l0uy0(HWJ`}#uG?r~g?&tsVp)g35cr=e4WA2*B z9mDIpp2?Qm{*vNian z!GhnRQ|{inwtfpm9^Zq@J!JhGw_dGZr=#z-2_3uM{(?i@04=Odc|Gce+urVIZLpe_ z@6*-d`_;)$8sYo)ym5v`Sk;<5w+o$mCd(eXKKJMjk8U_uA%D?kG(4_6?)9BlVe%i1 z;w$vC zN3w*sh92F`p~aNGy0D^ODqQ)TAC4~JETTKI=IQmge6burr&4PEfqsF!`qUy5_Cr0Y9`)|%Tp z<<@Y68htJV_-imu;}c~nJOsdRk}9A45#H^peAUgci@K)kBaD%(hs|l_4Sp(o=EV`a zU|cKZYf@?5=R!h{E7@}Heo=CV_sp!v*sA6lKu#sRe_33!Iv7t5z=nm1^6iM#V^5HO zw$RgVn(SH2o|P6Rp#I7~q>OCARaMf94rdDkHMc*PQ+}Nq?G#3-o=l)|JB2Z-te&)M zr!cT>%?@_m{_~4Loa_59Jf?u};5c%Ci+YlFm(Z*223dFDOSBor$yOUBDC{ve=E3Z9tu4Yxo+C-7So=xLPCYoS5H*Vs{Gmbb7bY zR<*SURqYl!cR!iMs`GwQIt5Bl!#Q5fhsxsc##TP*goJ*jL}N&H?;aGKgQNt@eocO& z4|0UI*87xb3_2&f(>FQ70L_){9Deduvi(AEwr=!7I77PAkS~Pp9@AtU?Nz0yUXFX| zLpk||aBp{`-Cqa;y4P%zi}yzpe9uQtsWO!4kb2ko8cuVcd*~1_$KHo|X0>|FhO6tz zWsk5*(^d9+8wafS2p!uxZskFbKL*2@AFM&&w?xx2mEWL-CRq1Lg=Ab#UQ@ATY_V5x z(Cq${qki)T>a!P<#T%LVDSL%;#)%uChe9twNn+1)_5Lgj&UlCp{}CeZgUTbySI&5& z*pX~@GeaY{;zoX;eWi4U-yCJcop6XPYvjD3G4I0)gU0G3xi7fP_{iWw#ruT2LdPwf zh@Zbh-%~#4#ZUX3`%>s&6=7)W+(-V}M8^At&{o^=APW+Jj0@#&Y~o^A6JWhkK160; zzL6+?ztCTmOmt+wkf5@?Nu|SJfV&12S<96C$v(P z&7%-GHOXj4+_JbUGOF^)H1$eJAeP`!Tc(=a-$4n8@-+@iC>7>F<)pu zF8&O%gU|8cEr;mrKpK3Ehd<|nZ$ESHIqTlY=KWnbEQUY=4EoQsqBbbr8t9vDqFwod zL!#zoUB7?o7Ey(Cw~Ei38Ez>gryG=>#qca0o1j}ifZa7giSU&j(zF#1`6zjCgx|X^ z?20zOtshx|U2Ry0q^?1+yYNF~nB;IA zzJ7`<@4A6Y==K>p@U<{Ya}=>*zCA-7jtV}SC9=)q49z?$xHtyOHWM67UX67V`lhSE9U`rO3)Purbmo-MS{1U4?wu0y zR7aQ5*3&|=_FK+NHNI|V`&DD^{QG}8LEX<_&a*yAlgoY_%VMTcRn~SVAI( zfWh(`&+$o$dNxvKjL&;2FnJ*qC#UFQJLWXgrfrIIUJ+(W+vh zeea$K9%<$mxXL|?+by3zb}QG)dM6JdPdM0y&MQxrXpcv^L6(=kM^(kbP|eO{4sQG* z>h~>XNZ-%RF9<4C*G1I$lCWJhav|kj5~k_CMJ!8CF3yw7r-B~e$WrX7`(S*Hf8-Nw6QIS<+lrm zo@nZ}!Ep{g)97}srs*Vl|BB#3##e=)mhZ>2w|-w>UGq53YqffHkU!pxZLw0oHx%dP z$6OVDH`c6Pz&gEm)5L3nmsL?Fn!91~J9Q3aUK4y;R}7Xv>?VIz4PDx_{71Y_8y#7| zH3&kw8%K|>;j+AVHVyb$2(>*Ci&1y54rR`tvV#YqeDZAC`?E02Y(qXgCi`x@j+MZo zc{K34Fk0odk6`bv(&y5J>%tEz`&`=bi{RJf>0D0NuFo-w9yv=jzo5`8GsxkF;H%m= zheB@%0WIq0ph-2jk&ZW0canYmvV)G?z^bAp9=p4NmUs<{OHZ!aK~}%Q`-xZz{8d<} z8W&4ve-#$kRL#baZ;LuVUTVVidUR%fP^sW$?znjh9JcUhh2%(-)5mXdP=9WwkM9a@ zczf>YyFyPJxztcHs|}M#dbP*42*>iCAv}ZW3p1jgYYF?3i!iVtYW9f31zJh01Z@sBweF3>`T{XVhk%Zfr24HuHv#^dA(eYm?s% zr;|S6n>igJ6|Zfid@X5RF6J z182{ViKE!ww$4q0XU~nBK6l{kS+P^*PN&S?wr^o|oU5fQNG&7;x{i=Km&9tx9Uu-O=>9X|z$4fX2Ly5FK=Bj=^Z#`w690>w zM<9~=2z(phdX95mkN;CM@jq2$y@m;3dkJ#RW)aM+0o9W8e<=RYV}X9+GfzeTf#=uh zT!-H*gM>8*hxOUbAHula$^JWzB7+nntSp1c_*If=aL-^f(V!Fpi*HlCRA!-n zX4Yfo|0iMH|BWR6Z#?~f^pp6HRDWmn`kb^hxWyZC8-_R4d3V-Je6_z6 zLt+vdB&wc!Igv7-*dXQgiqQ=`zwGH{`|JF~H3*|#=ViZ~$i#*u7iIr0dg*VN!3LA@ zum+gz_0rP&IcBbPSH*t*HTw1b8kmXFaf9+LuU7}g%DY~2s}I2KCH}OhUMh%tAeBLC zA(r!TX$v!A!2>A;k_9P%6hkcEc_6vIllVZ21IUE1Vh*I!%-Qqj#!QLEg^-auzKItN z*@my~)l0@p_Imz*GV@;LFR?+u|5E@B-Tm<)zlL_kS+C$;)^Wtg0a+3tA^7}ZVoJ-0 zQlOI}*I~X&IFNde|C8z6>Y>D?76P+jRd}I+PZ^UYLVGeG#ZDOwPR{a=)?XL+LhTVef~M558J@8|Ful z>%AUIW)QZsX_kn8%Y7BuF}+55`hJZxE4@ZK4M|I_k$SJHk+vJ;HcXbskn?FZ(wsFl z($uvz(%hsPY503Jl4DAZlnL3kqDJ}#(gglPIgAZ8QXHf=_Ah3ATq9kE&I5?cvKlFI zAO78fv|e5#&4YNrqf>N^^d`iAR*f_f@&V*q$YY3AOpR0nv722Z^)bjCm;>XHpg8Ef zgT&9Nku2vT0|wayH{WT5CjsF8l#_M&KEp8~1)L=h{5ITT@TL}Kr5uaQ<~ z)kvce*ZYb4P)AUzhWS1MI=Hb$GNu~I3-TFc0i?yI8mS*760#lAEq3)x=fS|WEI49ON}%FvH&6={5{~VK-QrC3n1p}Yb5nK)c@172n2EqVgth1qE^~z zSt~iH6iEc01sMbBW#C&G%sY)0o%i5p2twWjlT|Cd3p2Q&R*E=M zD}8fV;YNH_EA2Z}D_I<>O_VGS)JnR2wbG#6TIu{AMD|6klyI_E8YX|NPVvycuvT(G zpdS|3O2?1ZO6?(@;Eo}(CcA2-Uv}0?S9a7&Da2h^a~9BS`>RFOg7U=>n-&vIqXt=#g{-!rUh?7Z|WNOcv%%U|x`vz{3nC^Id_9 z|E`txHW20~ussp~dO!q&@t`kFk3;`ExoQ*ih_s`W5^@OH;}P^ zD(>}(YiF>_;XSRD_CvNq5;x#qGGrd4KEk>`Ui8fT*9MO9RD&)jtUGWt+}?ng8+6$J zA5Ur}HY;HMWWeWOeg)YGF(fQe>JQ6LR*$545DUn^nmm%)LAXln4CZl5g^z@}*7}i@ z2zi!R_+h+8^GF&Gxn%a}Sy3}@+W3*w8S;&VqUR0szWF1`3X*U$QK^?Np|B0|4x|kt zsf8H~vpy28yHV;#k}ss5YY+T;qeoIUgt?^#lQFxoSs%tIxOIWpLQa}KcN?4tiw5#7 za=Q#E?*?fN5g;4@NB9785t0pA0ufPS)&EjtBFv=6sDE%Qr*ZtEHzW>n6UQ|IAnhL1 zN>b&kC9&S&78G<)-cwyG9lVD|1$n!oRv3H%8N}V8V=V~~P zNLCmm6lPmU?eDeH2}nAmVK;jfegis9OEF-&2bji?nRjZX^0Hbf4H5`>a=TXA3|S4~%q)WW5WS=Tx+%zHeVA+}B;wydC{0Df zSO=Mm`u!4Z;a4=kb%qwpimhP(1FgGhQ>9%ncg@h_t7srz@o z4NLE}$oD&J+q<1*GyF9CPo*-V6*p~L_Es4g zXfu6%%eG_FHt@O}G6nZxTuhAVU$<;m8qc7mw{2S(52KH7+q$$~jkx$;YBxwLBx<0M zg|P?Xb%8f)BU7VZ`8RLddKq``+R4jH=hdxOmma;kcGr1&`9yT}>M_-;OSc}=rg!(5 z(z8oXPoJrt-KO=N)?-?vmv>KZ&u*R(p7{ZHY&)y14YwWIczE*N1w2f2@xE>I{H*)7 zfu7#xryfaJkQ9SN!(_3C6hTZ+V^o4fK++)aZbUjqvCzZa^0AZxDQ2_DV=2($vEB~#2|gSWK)AZym-x0O|J)(z5JxwvYA<$ZS;*M^zT^Xw ze<_d>NC3D}S{Euh(5MdLbafaibZZwn+(C3wCjnpYLN_{y9_l>cORBXBuzN`D&M zQFK;Yqiq)VrA(epsH&sr;E>DugYHY?I1%`9I*Y*B z4<=`Kq_Y+{b?|)&r{v`ymxKnl2Q$FkrpnHuJuP(?Td4!U`46KV@S~0gHXTksxFgM( zz(K?5Df7j^vBRlDC(*fWE%4dl_a$z?&q{QfQlk9EEdjl#d^pYRgtYqshXvA>PGT4H zcwp0!_oWQFyhzkiMJLfwoeM5Hn5;a+UTQo;V^kbMBR#~v=H7UD%9A(lOQCex7v;Iv zLu_dt2hRS@`_eob+EHvldJoamJQG|jxF>WxRdl50oy8XF>)<>mQLoNoTXPLga=A{v zFQrod38FxYJBwO1UQuI|5# zq}h63T1d^tBHgK;qM-H%7y2n}^F$cYz`AX8-VXn_HhXIxZS8Dy8I*j zx_gN_buG9}yXhk@WGvlFG*#Q<1>Hpr34FNFNG}sk>TqDk96IVHI-92gr{vt1hSTw3 zqTR+WqF`PCYAYywgz+sDK+i6so%s`Rwcr-e=ni&{G@m(db0Z_4FYZg(tcL>a!UYO0 z8(dTB-^$K`s=J6&)K9>9=hC>YsB||ABcr^pXn9vO)G*-mB0Ag^8BPH%FQQw}>68b& z>C}DcO>PYSR@S3dm@GF9TBe$3WqRt&X(OW$&{v^T0-ZC|UqpJwdW&7vo;YO_c!t(` zqtL>D{m#;1#;L%G74bpU#4?FG5O z$!`~0L=*_qi}$4um5ko*CVH6{fC~bbD3=>~cNg8%rcKa0E^>yPD5*O=Xmt2E^6ZsAF+j50k|N%b-L9a zyXJDjOF^XFpuRnka1N>X22JXTLg432bAP2(J<%FNfCEbJOFC-Z3r*@`PjRTa5L{g; zIrS1}sy*@Os{1Wk+Y5a=7C5JjF7y%ym>&WzGO3WXbn|cYWAEOgy?HITY|{#flzuv+ zx2WytiU*zSEh?lS&J8lZLN(aRa=D3Wh?V9vM(;B`-UUF%-=cy(?=7}BkB3FDsgUl` z<;SSON4?SR^T3@2cT3^Cd__AmJ-7sI1*o10lr0vENdkml3PRmkeVK4NQgO9AnBtiW8fbUL^d;M76j0z1*3K4PyH>A;qr z6%tBP{&9U~fzx4u^<@&p|ZofPPVD7{GE5944CxZLSv z;fM5H1ulxJkftgH66}XUanAP{;|u)@$e*;~Ze! z7P9D%vbYXxghv&)!SXKzq6g=`n@0A>_#A+fU1eX;j{b-@4%jERf*W)M#@Nzzq8U~9 z$M}{9hpRZ68APA%vui<~14M6g%jQN#m+;_DIW0A_(^Ap^WWpC*`XTyg01^=m98^f> z2cUsx06#fiAuXn6=)lx;ATo3noOcn1h@GNOdM~9$L6TlVL(X}DSL>939U!)2^0T%-& z{Z%39Y4i|O%8&qbJL^_x84|?=h=a|;fOGKx-DYa$fkM0#AiA4pfzy~&;z87#9Td)# z9ET#2SK&|uhYhqe1c3z)aSnazi?W$BOw^jWw?=wxE9qjbT_>|}Slq=*IyMa9 zWWbUNOU*EhT}80?=qe>Y#cR*uDArnV0nU}u4qA5}#Tq?a6wKV5kz$uhYWz@at`2~u z%!PIgM;XNe`?}JF;i$_j;7xc6)k$d-j)9z2a4Bw;(nh5b1~F&pf(8e!HAf&)a-i7U z+#g&yo-OFgqq8F&4@CA;nCoDOGz%6@M^cRtoz04YFLkV>y}Wq#8-ZE00*t<6rSyri z5PoX}`k^}}@}Mr2ydL2y`<%IGaOqvSsFv!Hx3UqUy*dk=rW>h7VxqYOoYRdwMv5cN zUE84geJZ81%IN#aNK|=Q&|MnOl{7EL{f zmW;yUG6FbzVx{D*Og2A_!l0A^?$A_v$o`7heI_{vp?}o^Z(3W4E04?HavcPr*xcHo z@1|Eu)095`aS(R_a2XkuQUW#m6s_j_AhCt{CU7O2i(9*(Bo zYqaQKUI%XL=1QqVSzyMFMptpi=pXbkts0FqgaPM%Rw)gp{&%?fjut)5v%%$kUMb~r znYJL;F<4BOgLBP%aMpMv{*J=g z1f$Dc0$2Psc?6>jj5?ru9-~Q&J%IyH&|1dfz?MJJ(O@*Q3}7F;NTM4xn~g4R8G^Do z3(g;Joam}7czr{V=UQ-~;092$jYxkKIJFKlO~N%=5`w`z9@zT^{SYE{QRf2Z+$5{9 zh^rL1;uiH~Y>nB{y^LbUV!-zW*5M5%50&-pS7Wj0PXJeXhpvqkdzlyT%!(JsU>xN| zx92!f*YXKCe{h)kxG~pOqM^ z_f15Xn8BR82ZqnTDy2f2vYOlU8{DSB72;(^7%q7<`TY&CwOKAWOS39!8Y&JluVYW< zRmwPIM{%L((4L(!nwVG7`=R1!vs73jtgGnvP_cc>L$H+Ts-!`NBuBw42B&LXg`SNm z0;At}aj3ZuhVqg&Rk$vaN7~%+qA)BPoUUz^gc>z09N)tAuCgdhg_}3rFkQ<(Yy8gy z*BzXtf#VX)1?StAtR`?(Fm|WDjIF(pVlRqe><4_kJ8hYOZj}O@+N%o7^JaXl^~VHJ z+ddDReg7(HGKcGLr3+ZDO2!kwR;H&<%9|i1a1Vw1=iG#BY1o_S4whXos0^r*mMdK@ zOTw_8^#hlgLR-Q(EMQBb3(Thj2NG2=UkF^hmz*XdjtXGwFKO6B%szrQy6=}& zQkAlHS~pR&QwM>|+)sNZVx5}~9Cm=JCW=nxdBCX$s-$71;ttXd_7e@f^&p*RoDO{bAXQD` z^a9r%B&W%^AgKio$fq%rdDugMmWOD`WN|?EDB!F^RZ_oaaV(bO;QCL2+gZ4UvKxLn z$R=>YSM+!?;wk`+{fZpIflGmlzoNd3O?zO8^c77FN7=Xo2OX}$XP4x5m=%tC3kR2T zn2v@cEos1hN9bO-*rihu@YN$#(s+(cZWks2D^$s*Dt|2O(KfiPmqSM=sKOBUV3w%e z=!s?Bv?;j82=PIi`I^3*g5e?!*zYpk12!)L4!Bh%Rnr5$?Cn1l-PE)v(g*G-9nVA^ zBu*7ucJK#x2rtS+@C~mkV(QnrI?z$jDY;Fjry`GOz`8QJHx+p}1e{k!;xr6@6~MW8 zrRPp%DH%Qu*Y<9`Fa-Zb%cr3|h5&2uO3`X%nmIQO(?klmvv{ZK17+&?16-#(aGM@f zNi#V;{#KSlxR1nHa3AU47!Nk5u5IzpA8UCH}v#I5s;3&ef!v?52zD&B|dhwWy{c(?u^coiA$DvYHa7i+#)@ zV2Ns4O($6`1C~^qYN~-nT?ES$k(?uWZUl~ZsFq@td3kmuR!=^C(8!#srFdl!_#zUS zjsjPU1b%`<^7;l0#>WL%C4wu=&5s;`49?LfVvkVZ>x?LDg{GtA4F zqf(-HFadYHCvAxmmzWm;hx%4aiCoWbiZaM?H&r&YKa%(?oZlJN5ITS~|ObOz>} z2yg*I>BJ1|2wVboA5I=KMF%rIaKi9vs_rN@Z(-dZSJHStxxJC{bA;gvZj+*5OSv(k z>6`vwvY|DamCy!8aU0<7i7}gfM8LiLHSTi%g}YlIP6@Jq{MgSXaQ=aEGL%@_9|98s zt?{g)jK=;LjsrLz?r~S)o&ooz$_N_#wm8(xe*h|AL^XXfz^=Jj1T5vS9D_xj0*n1f zy7e~tMJ})}z9tflar6>!*eLRd244r96vVtpvC*Qbnd3kVU_naRIQYVn8&oa1aC-3L zR0n}84x&9AQY>&q5MAJqGFf*tJ&hKfJ&J(i$5czLWM9gxb`@L-IIJ7xpAP>kz-=8v z!)BppSo_01hGJ%k4lO)^>!90OQI+HM2WKB#O;QgmtRrA?3#JpZ5OF%NZwOV*!f1!j^kW-TiCGxW?&A#Q zkpPSJICK=nhn%i-aF*k!DhB0|3+yvvqdL|Jm9l%7Yu$d zC>xyxSMmn6jTO7AO^2Yvh0@emT(h_X7lzWRSg~#UP~g1r)e`z{gSI(K?gGA`;^AHb z_X=fSuO=3Q!y#}f6RNQg^jeICUaqU1Idz+ZVgCsn{3loAYU<`byRMWrNAw&M5r9lj z!--BM0>6M{)6f+v>?aLXrW`J;ROm!NrzPv)$6O}3*an;%xLj}v)5vNr+Q)TZ{WR(| z7t^riQ0PX`%(J;o3a0 zOWQnfp)u7`c*C$%!E#_6RtelU#ZZ?xgk>}wjb=7YibFnhz=5-A3G;!#=`wb<(7{hU z>?O15hdAUh6WA}7o-!^3#v^b}^Wnb~7|*x$osSCFAR{4jC~`igM{nTrIn~%8Sob?B zFMGb|t4;&w7f1Kzi+x*O0?u4eEpa^jRGaMtm35ANziz_sxtz9Y6BQ3f3KE{-2_;K~vt+4PMSs#v8t$em9! z60;d}(AA%p|2s#_JAjvc7{U?+~~U zZ~@9Tc(-_LFk6p8;Vz<>codW;aM~hT%Qy(QU=i(!$L>fraK!RzX{6FK9pA+ib`@O8 za_asr3e^ZH$y|YV<=|2(6xe?y9b`TUIBg}}05;DC_Fh#j?V@cU*7RAxN$*p+L*PxntYx zwe+`gDYlZ`1HpxVK)V*9A;bc^Z=?&05LOuIv7Lq7K%wg zqJ4nd+uUv_a}iX$fX;L#l9Xzz^P}erKw7-S`X)8U?vt^XHE}k49*Wy4xJL{ zdKPg(BZaeN(v=!EtZmaNs_j-SJ~C2V5*TL1xerU>1T)_>P>G zVz|@;SA0h!m!iDvLy`6?w1BZ6ux|-%St`zKnG0N8fiv-jFuY+Ffx8NBxv~k{>pcvm zb>KYp)lzeVo(`rp7COFqig{0TYT*r>3U_CNJLf3?T$Wy5+t@mBf}=o`K&f2=r37$# zJzYa2>P%qW1A5B1066>sIV6kDy~=>y9zGw(Iq)aoT)}aHKP#{xE6qS$h%;wD0j=~Q zEr5TuA8^`3+LDZL!+|p&(ox1qzy%NKMzZKMI15-)Q!P#7@OZpRHkq_s6)!gkj;{#r zp|5f0Mpp*+>>3)7f`(@OCVEy4#iZae)f?Cc4;+*#i@v=nVmI?NaD{kC0lSeZ>~gD? zVQ8rXm;MJ$Scdevh9Uh=={?4Qz@GSE`7(qX4_x~f{lGX2c#}k`<8alevA>zyBq(U~v|=n1BNvp9l7zSM0RxhcP9jhN#i>+I11((x7|7KR6Drp5s)6 zf~y55_s;quXslJ@v$GuWP~Zq(Qh4UR3GM>i+jB&60E4Y`;m>cU9)i2;Yy9)La~1C1 za9?fkze2@#$>?woI|~Y0BibigN1&>qP@ihfoh!K1mpC7ADc~9o-htqfUeXH(m+%r7 z2QL04E)`r{M}5!>5odyoeMvDFT=Yv^5xA%Z92fOfa1kB#%GJ;lSmHX;xV7ljt{C6# z-RZrx-1C9Ay3;Q3?c;$nI_Z^5x%#>ptrV>f0^9`mEVysvCXBuC_pw=00#4&WUEar3 zU>b?~^`NQmV}X+w8N$Gw9JaGstt zEFB9b|F_U~eDu;>=d z+=M*VVLv?xZUy~l*gE7R9yr90yRdvtW8FHjtNA5xncz~C4XeBBaI3|72Bt(mj3})! z?&{X#irEv4Wq+Azt`365y*~|GFFFl~13uJW|Lg`cH?~x8dEm@BIruS`2`;w*=LRkp zTuy)5wO(wScpbPD?hPBG9^7?s%{UPJxHwE_qDa8mFoB~UxNefecLc8oFEWpx+@-06oo~B{m-!4-Hpnm@5IvOYk&sI&ewM`SZ?b3~!AM=7k!^ zlmqu9xDR4?{B)2)a0LVC@CK|v%YZcl=?3sD&D-d|1NBlkbP$&1XkPd&kQaV~I6QlZ zJ9J{9(~Wh|FqZRCmeWeO0dUKJ8?GGKKX$WCl1(S9P(>Op8MvWGL#Gfr%alu$Wf@rc zXM+>`xk1V|U=C+sYA*#B=17z*slWLhg~L zky}^Lq0li6pamO6=axypmP7T=_Nh288Q|=}#VA)EXE&nLUIG_5l&UsjQC!kB`yM-J-FtaKK!`sK<47IBg@bDoe1b03Zxw$q06TN3nS?KN7(;81ROC!kDF4LXJF+hY!=G;q`rVO=K-G$rtTL+=Qh`Y_3+z?{mMP!ZMpk#xj%uMX^0+s{qhlwJs;y9 zvip404Y)||{}B4D4fddWh$_}}`OsG+1SIFRGG z0Fj33@!=iiyv7#Mr%4DRj02xNUXN2fe2CFFi<<2hZH;mAvAbwz#akXm#nAAapqGAD zrc|#_M9)U=VBnuXk)Md|G=PP0{Xp6A*!zj-{)LWJ2`^N1?9;8@C$`l$0IUuH6H!k=PebxY)Vt*l1ztA z8g!n>lYyg~s?y53e}hGca*h{Dp_6IAr+k|QSQCz9)9C)#OB(w&Zmxdzsn}{};JavV zQ=j)G&QCbFikG-Ja8JNB91&B&)xN}Kg3~wPbO^AMi(XbqxE4YSX z*MZYD;JDDN7ouHGqqW;G^?3qEPoq8CL}!Ok;1cL+p~F8NBpO^Pc2~EfZ=?geM<_TC zINpG-0v8!@9kBIuMMt*?Be8-L{eiQm>m^*;abK_wlqc)uCYaFq9;3Xxh=NYpa~;DC z>d|QTCuR3kxVuI^3*!ZMF7Ir(N5H+|3{e0sJW{WH)~L7uE`bb-q>))D06lPKB*kQj zQ`Mp9sU?y0Lzd{&CIQ&!EkgrEf+xwn7OfogCb$W3JI9M&Tl#2+Xw!uGV(_`(6J)-h zC$3wq2U%I3MC+4JNy@n}T8!lwlt#gWGPU3k{32y9A_|la?(R{%qLx>u-|rBIn5ThD z2lqC2z!v29IZmCFg3AGSiC3%+wBd8yZPP7551K&-KNp?ljvEO3rMLCcF}{n3Q*7DT z*UbXw6GQK1i*4oOr6sV($I!KG6hVB!~&#V)uO0jJix@^NN$8JJBAY1l4tWG|oh&{P)cB`+i8=LjPZoY5j&(=dfP zm$&6+DK+Z@DjM#di|FAljK|r)A&bakH+Eqz0b3?0SM*Jipr{Aoo`8#WW`$tVz+C*>uDQAtmdqrI`~qcb zxeRmXd$j%wUOEHEC)43CFm8kbyQa{MFEGcY0(+;B)gI{N0;i==cg9zN%Tj349_)hE z0f#TsOIwt6LgpT9vU@H^R+rI1)(r&?Sxz??CjsXyC-q*$lLhRyf;#L)%hn-lC9ub@ zpbKzo`vf>^#q(?8<*MOU)?<|wxEplsS75GLK{mO_hd=Pu71S5FQ!KE1s$SXv9lp#M zzD%{;bkYhF)pX@hy+7y-=ww6ZJKWsIy5>@@=qhh5UkC5Ek``V-n3`0~^{Z&d1*F*% zxNa3)xF9-p2my9mjh@Znql%WJdOTIw2f^0lX;7|^c<98frnR{^$?gXGR@jSI(*)#G zT?~xRjxOJeaBG3%(`e6L^kiWrT5lTt4L@ytfQ!=f%AGVh4&;5*^Sp=3?lfQ@!b<^; zUqdnb&_)Y^1J}~7eF(c8IOKi$j&%fF$3(qPe>3mP*EH$W_Dht1IIw#<4f~Ss5iq}A zFSSwDL|e~ejgj#s4i*%{K@W#;W!Sp%C3>`GHOA8odg(9bT9EaATt5YXE7?F@_9K#5 z;DQXAupb#q2QJQ_h5Hdn0kA$pj}z7Mg0gTwHXmxi1$;m^_9H>|X(;p$NR@{~`vX7u zfIRZhz@mU7HtKO)Tpl`S=V7GD2A2meOc{3f<>7W#8Mv#sV*>x?)@v|wk)EHJ;e9{h zfN1X&04@t$JLHuc2ev8YJ`)bUfN0nOq&ErpI?>DnqVxD{VE;|}`jZ991jg6Ar%%e) z&|JC2&`E+$Acu*{GAyt$1F5hw0inz!@+kTQx>?X&s*IvId?z%+<)j~c`mDvs{h?l( zVoFw(xM$MuAhvE3KV!}bu-Ju9vDmY7y4?iBLu7XS1LMIN2-5rGYG3dd) zwd|@iNH=hKTgWCKbrS@P8%DkIQQmRDZlBPke9>b}HgL)(`e#oJaKpCd=LN92Q{S+Q zp_2=pM#c!--^y>KVYWz9W{UxhL5D(Wp|@!(RppE0)IsSe&uuj9km%6F8*Xv1$8Xn5 z=XokZ=gSubna=@lou$XN`Q@>8qO+)tc*kRmm4gq%CqnG+Xm)q79l*z!xA@b!g zhZhHTytR1!VYKb7z_{Ud6#iV!0t>kf2f8=q0_XIXahSQ-{T_m0%HarFrz6I-OS#nR z2tPan?7NR*fGtvhg~(e$ zcr&$V+rgSp3rF?RhpgalC4?+D1nKVBjw~8`%8gtc_Hn9KXo>+KVIm3424?)9Dkf1AHxJ~x(O9^g4z~B#|^mX z1Pv>MP6+T-yg`|95^$Z&JIl{5nGIZW)-Yzt6W(OG4+toOBDj^q%?23dtHJqK`Qr0Bcs+P?=JE4} z=)qN-C7Y9CmjP~@!JRW)b)r$d0e?E^_<{EYUjS@`m3;7W6SNuCXt~J*G?p7m1az*R zqva=2KASk4^K|$mHee0`$DMz^lf>(>VsNqNsS57q6~IYw50xKGF&;rT$Kd#zE)z|! zA^V^o4$X&vy?UM&6k!)R3D~{(`Q|~x`@=fKu@&yVa7UlvGVmP6jXX?Fu{;m)qN4~p zhoBRp=qPhl6m(9X^l$v;NqJu`0B#k~(?c(U$8fn545AjNaL>!H}W;k%> z1$yrkDk=>)_X6z!Z=MJIcESZHXdlaZ04QBj8si;Rqnii(Pol#DuL*ufq$GAt@8>QHftij0bkj0}s4 zj67IW+#*1P5y<_2uf5T<@A>`b^@8WKKkKsBUe{;c8EJ{wfrj{{tlEvcByjnca{q4J z<$xXa-TEiy^499zH2hV{yj~9MrqObNTQHxZ0?$vCJl|*dw@+q$N+yp6hwS4pal)1Y zj@>7l;cW%r%6;9eEF7a0k%mw0LDL)HuKIc;B8<#LiA8%n){q6^tqVH^U(3Q;`vk9I z+QzSCb*=quZ(wc%eFSr@eOax2jH2?P*pj4P&|GVuqo^jRm*mzGh7{(0#?Z-5DyVN{ z-Dmg#tp283|J`h|D?hU@P*mc#YNC+grg3uG9=oO-M1Ci;_Sk28JxiW!lxz3cPxl6v zHg@aZ%9?oU)ED>I&r+t5-^+nL_VZ=}1NL|8gH|^q6I`Y=+lM?id3jtiQg19arcB+Q zBaxeB>F4${y@2^Y$!(w8PggMUXW9O_eZmF6%%4YED*W>2FBh%^?pSG3C9eps7;YX| zRm-fZHq_e+_}ZUkaKu-Z_fDy!kyN#`cL|Mdi!oxzW~7J+237yoh{wS!-Hl@ODGBn4 z8eTK}jK^VJi)^kZfiuB1zshU%XnsZDRljxXZ<*D8Ydxdrjc^UWiQhi^a;e^Fw@i$9 z9=*5quklrtdz^5IaOcSP`|M|0Gk8pG6YE#_Uj+8=kXc|`4Y;zSThEs+1R-N$rZ|S@z!bNteDJa8U$agG@DTd4IlI7o#+3Uc~U2@NN_}>S1b;+}e z4|$Q=^$*$moqe%261M zQ3R%bkJ}7zVvj8Uo^{lv;G7=Sv0w8x;V=5$?*Bv#UEe17m|j_@{8!Q8{Sq4VA(}oj zTh@I~7cB}d=aBsRJ&QBb!DWXect7u|1h*WLwfhNw3plJ#9#`1^Wum1|cI~&@eN-(I z!E?}I+4uts9CE=mhh_f{=qRP&zQbxr+AjW0bPbvz>iXrZCL-MX71GAl%~C|QZ`zXX znd%`2Yl-Hg@7t}TVlnL->XsQl+9!?<;T`D^;eU3^D-fd!cu3{p%OCA?B^|}h+5qFN z%i4WZ)ZS(ItjqR&_TbS@6+E89-FxJUuUO-d$wLYc&wPbHMLgv5@bOoyNvP$afQLVn zNhc5G?mgRv9OFm%zDklRgOBawE>@LBI7GL5&;MM|rp)6o5Apbao2OwO@6jV4d`%ZB zkB4k57s|n}?c>H?p%fKEm#@IUg#kMO)TZ<^8th|@V%-fN=h-9w`r1C(_`aam_zH+6 z4fX|Rhw}auh*V3Dejiws*X1Lc$Tep5U@XrH$0!eb)s`OlX9IiZs(9%3>d~K7T{63T z-C!SQj2QJP&#XP{=-$~u#!CN&)p;RKrc}fJO)j?f$e{)nz9;k0F6Jj2oQ=UijP|U;UJlIlr zXg#e*A8!se`_$V5XBWZMkL}Sb36^S7V^vLh*=EZn4{|@Kp}Ku+=)5(`*MJ_G^n-n} zQBu1hF5<=@)|06HmW#i&PaUmvkEl0@mvKFE@elTy#>b{Z_}Yn^diz9UaIX*|$KIp+ z%fbEj2~WJLY3^%fO{qQLRMm*9`02(*^mtN+2(vogB(lbf-vNrA6Py|(^AAw`)4<(9 za;?Gz;7qnJfCH-(&&54U)EDtn9@fK!2g`0{*99&KmaYSoj|j{{DoC!$B;-@}X=_ye zO@OGK++%K-M>95-_MwQWqX_&l&%nGDa~oLwl$%_*7C4pmN}Dh=mmB=N*^2UUJX9&> zmMJ|WOaI+7WzmcFv6n0w%{HchMIX~RoX`{)@jZ-#VjP_5j%%l1I_VO-*|N#&AEe8R z$J;qVk8#+4_@dM0+yBx~#DSYn@6mUe#b$gneT+P~o5X33UjR9VYgB<*Z@qZutE66~5SKQ)sg$>8t^ z@jD2g5AKYRg$Ie{N^rm&S*vifvU8Sf0o%OaCah=mFdVq%HR{DL586+$MZ&q@4x9Vn z^n>L047kcDner2dkd%PK=8<6tllrMhu7nGPdslkirq=AfjGaB3e!`&(gOc;)g`ezG zr-qWNUFY@a%ap5Qsgh}EK*sVpC+1<%()$yEOao^}OW@DAD+ISh_vlMU+-;_V6tcn8 zoK$wI#5`buto>Pi95`u#Z26gqt6^~Z2zIlp_ms;xlk(|!6;v(RZPT*pdH*mRdqf};GFM7`ZJIbB?H) z`YV1EDR)j;rf@Yl&nfGF#lL27ol~~_N;?-&Me~1weDo`c5DgAlD(zrf3OIFX51Y^p zRUrH~dz7^bu6wDh`wjn^!QmImmftvDBL00MI987ShR&W3Zn{VowlV@x2hLw6_q1Za z8{D}}cC^~31Uq(7JzU(QpE2?c$s?Vq2>7&%k!P`E3;Mv#?VU?{=<&O^(*m`$p|Zro z{dS2QZL`k`&H?8xKRHZ6yr&4hc)2WVw+BwH0+;{IjuSf#@U`$$jM2`k7|Oc!Z<^|o z(H>hBbwd5*G^+KWYP?+0qvzv|k(>{DP={=`FeY$(#zeisi9JWWY;5P$jy&*v@jYyK zb)UvaPD{HzV0ty2@5&y119nvdv~;s&nK5v%)*LucdAbEVsVik^2Wwa&c=rF0GP6>4 zbl9gWEpM)q=SKXPVKMwjHX5Dc}5GS$!<*~8gMbe6!yUM{OU z$p$T8+tsq86Rpzm5w-R;Jsk949I(*Y$tff8a8+;@%AD=!CDVSVg3X7kOO|E7lcbg4 z2iC}Kzmr8f!S!q8h2I${a(qnIxt3eJm9jaL2IPj}N>$3A}nHN^D|J!*oz%kCIcL&BZ7 zG%Z#JyQrqqu@#;w)Bmtf*-!|sN$ojy^o}{?#L$k)tReVViMi#*9z7MTYEWa?$K#sg zoybt=ChWvx=P7p{m^(W@lH-v+68Vcq2Vi9Rgv_?C$6OV~m#|5~?DPa-(7jHM5+JJ+ zoOqK=?FOfTv(sdGH-Rn!m#4}7-DIN{aMaB``WE*6qk0@r=HXPQ**A+{52Ys&>|8JN zd+bxDXM@w$liUPAMc*Z=)-g9mE>Y2@vR4UqTp<#cHVyGNiwknkEVydWQraf=>gx-6_it*_RngQ#H?NoDcnpxoP{{aay3q zau2nVVcfZ4Sap0xF}b%#?=r&}kFvlCN=CQ%pChSoeEiRe-O?=7t8v;aZ?I)U59<_E zhi*0_*e7*VV@EGPx$xtCB!AU7%i7Q*qwLyQR&XDfGhoiK?jen{d*oibHgT@X97zz_ z8+-Ksj)coN+X)@!H8W5~Qxt_+4)&rpk%^2khYcP#_?)nuVe#nH6Y3w;N>yXM2U8_?P7V!*pyLz>P1-{=*Dc)gPwI=z_4ktOynleZdF5EJqL9r_PTB zJ6}P&HA{1hp>J5gjxhzU5U$kZu2)&+#R2suXrB^N-|PWgfH-^N&w9kATbiSnPxLsS}gH$u)nO$KyU7E)A~KI5@@Q zUU#FPAdd`^6KXK4{X||KB*9w2mff;?jzz{l2(AN}+&qfqrrtny#%2?|yMzf%D zSv2M`pUISA{73<3erC9{=7LK;ll8;AvlQI$ndx^O*lmxAyTRcjIG};revfh+c!nx9 zQ9S4D=`m+~sjbxnmP(&^_&oS$%#Bi){Ym=d!*zb4dJQ|TV(a=7fAS3taHad?U4>oX z6<^7LKWWIrzaf)+)x$P=_6c%~!ck_0a^TKnu<|IiZ6&zi8`*Ib1;7Q)_*M=a<c%?DLJ?If{mM5bjcVbkAy^#O*=ogr?(9P|3%eFEt%+?1V z)~vi=`Mq7+)~AJ8qZ*%{FB_N_)2iX&$0u4R13JYrAHpS zhUIq6?wZAB`JPPB(!-3N@>DDyyeJOtykF?gnr8*Xd1wLFY`C~zWvvHQekC}eRd#r2 zoM8a2?(EUSjKH2nvawR|B*o)`(H^fW>V!&sv7tmp?k6z6OQ5GVWo8n%`S%`O%(zjC zAdQ8SdgpGVvQhaU8#_r|J*-$X(s7fgHqllM*V)~}ihSevk6oUc{bpK^lisG9zF6G* z{y-V+>CqQ@^I+8COOMZdUFg^Be#_qizGSrLiFKG4@W%OLs1mUV3lZ+Utht*Uz>v~Y7HyiX1TJz7k4jB zoAm16!l1&g>Xvw{`Fi%sxnA02Kcm)#NcQa27x+k*jodkGF=~qm>_FJ-;}@{xZ^H`C z(VlmSdzfZ7rkOi&9C1o73zUrgjUiSoz!>ie{gGp2{d!pvt^zpWA15cI(Sb?Ciqo%G zZnA2VM`iOc%)`H|d|f#YMW^;M!8!R%)^c--nwR`&)h3PVR<^WW@f@X{F)HW)s+^-& zW{=V)j*8(Se0;B5s!Y;&2np>-akjJD1k*Qvoy zYoL5PicH=Kj+h`vN0Ip*s2i3bneMFxTcg4GL9*Oin{UkmhXl(OZ;gF;;P_y9&0Aym z8(hl8359Ad<186%)5hBz%``x8oNTF1oV>`UEwN?86>+J;d|A^^o%4oGJImGxmveeA z9RhP#sgE|-8gY<%eugaeAzX>zjBr`!qph>mg8R1Zy%}^kTVfw6@$@0d_5x-J`YXwia;el3tXyn~zdr{e7ti!hfdt zERlu2l*nZ85zO0+bt04EJ-%d=$E6757&)yL*tzGy$i^j!wWudD-$aTyvdweZBE48t{i;QvF zQfxL{DZ5VL+Zw>NSM{3bsf`m4KaCT5ej&M%dKp+XR>Q^kX%V($xVWo(QF4tfdij2Q zS1DY>)w0V^TV-?m)y-{ha<9H$_1(tFtW!0+EfOwsO|QPfTxoa1sTzYvaJkpYBd3zg z1>n+a<>gb!3YFl7Yh~}LBzZG9>AGHZMBBagK(AtV&r3bk`e03F`)gj-(BCMiH_Ci} zZOXJbaPy75Cog|dr_Ag&51C2BJY-$3{;D}qQm)3Lp7GZ%vNmFnk|tevVs&dJebZ$A z7-qC0#<1#-yTsjMZ&pOGH5OcQv#cINe#!>trK^uL7Wuq6h7YQS3%^yq9fL=$;F??I z=os>OKpXl0Hkp1Jenf#IZL3M+l~G2oJodAF z+>|OFsxx~3&%jg|78@~Z$dInnc#ox>j7raBED;(CP94EcaN!+tmEu#tjd#dBW3{Q% z^1)em{_hx5*{B@zD$MB&tEs>PV=0^79dvZ>lHdSssWk!Im?`T5v~__sVDEc-k1ymg z!Uh+5uXF`y=B5@)C*jDFK#gw?2S?nes#D`c+G{jzt}O?yG`m-yXr9OSj;8&?YWbb` z-zb3&;w}uFvr!g02uCWoWTV`#a4EQEqwI1J@AcrMP4cTl<7Bfgy1kpkKAyM<2gm2g z;_=u?09WS7I)$^q{twFI<26?DgY!1aZpAl(Ee}bTa%=g6^m|AG1690&9l0iUf@4Q; z3OF-Y?ooDfz@@peJy4r6stoM^aIc)-VjpKLud9QIcvyZ4#A6q@;bHNc01oXYG9Quo z6R1Tp!3`|QgSVA{qw;!L{`dX_Dx-QHJGaQM69}UVobj0W1<_i>lU|M<(&n*V_V;oW z!36iq%py-i^NPfzYXQdV)36hhFP8`L%0h5UzHAI4u4=(KTjh-)ZAxG_xN0k{4t}a% zD1Vk-;%uvQVLmDxod2(0`LdrAb>~jhW?QpixXX9lL_$>xt|^emClaGg;QDQ{Tk)1d z#L5%WHIWo^f)hn%1#7crW`Zq+y?VSmuTjnWa@F}a*8-@{e>8Lvb|Rka)lWB zwc7+2vR!rulQZ1;&%12ymE?mp|t|8 z^#j>4g>UQwSJudZDfk=WBF;V$pVLXvSa9U-USrqqCF-M6Arf}?9^Z&#%#^JD>!Wiq zPr>|d_0cr@^g9?PUPq(oc$=+&=3p*6Vf46;NG28}<; zjx(sFI>G)w^|ESn<@G2Rznr0+ZFLS&&^U5+Dp{%socwFAI)Pf9{jqJTruj6&)xeec z$c`n<8M}L)GSWYMW&w&;@=O|)pkcCekMvI^yE?&@hb8z-J|qWR`e(0Nw|*wyuyr&o zy3>fR8cZ53hxBE#^Gxk@TQ`rxUWYhf1B;wLcqRdl{gW8;l__D2@8p0pPm$GOl#Nnw z%PF!kOywnT<7x7m;$7g-vGSGTLyz)eX0^k#vjUUAF#(5;ZwOU2c{*HNfGnGa-6C-O zIJpySs|APJ59wEo9LRg7<}KCJw8+2^T`7!zc@m8$k#JE=5l$x~W`I)zW%+b!yIOEX zpgcRB*ysjVO^`j)$>0HQ?rw!a+#Y4buKV+b+AjaS)9z(Wz$k2@%$lK1U6c*Zns`Wm zSY<`Z=R;~G>t;{2(D`PDr(ldVt&12V^JPfEo3$L4D6CfEt^s!$=JB>K&Cn)U``{eG zvUi3y>lCHDhr7GGB?l`zws38h`v#d8u0HnpTzA@^13feZEC``AX^ih+q6S0 zKIT}$31XS41^EPdxVwc+=WZrH*}Ih!saN@Bdw8Bb${aEHD@P<_ttd*?&D4U=Qq^rP z&k6Gm9X}~kjF~UdCEXuY7mUFn6<{WJlU9R~bFBMl2=V z$PHi?oEkkcMywz5L|ff#S?U+>@$BDvLrX_{KI#E?;)I0iHpk#x-C~}}Wnj@VXSQ~p zEtSWN4crYT`~F~#`3!k|~}pJYRG_dBjy!>~2=#_)#tzQ-_L9^a$}bV{Pmlx+Mw9 zj4Qd^Wy~iit8sI*NMm1b8GOtW^3fb>mj-a-liX$|TO;Y^dz?kJ=Bp;}o{}kNVIB!C z1v&dp;aQATE*fe9H`lfWxpuYtymT(ngDT@oq_WzI6Vv^dUK&8wHos8Jg zo>tGlrIs4Dg#dx!LxNa@P52fBMmcZfF5Yw>8$`+SXoaigQ_&p>9{A6z$P9z(J? zlD5us?5UqWe_3$; zaHNXyi{O7g+^7(F`CKBT1{@nA2hP>bG2+v53VCNTx2dW1>DuHCEY>|K$w^+7Q=+jJ zaymEum>T}-D7?yrO9++6qlnK6aMT&xjik=VUFOazpL6VEPgQxt80-l3b9YOeF0h4xOt4~L< zQHn%_F>!XsNImxtV?{LMQdb&4y*C_d@wmyGEmzG)Z_Ne=MaU!IRppA0=+m!Mnk0U) z=Fr$4_B`G(4sI;?55cGrdo^?V^o6E9ChHjAd(b#-0BfO02Wt$eB2qv>Nsfg@wd z8@!h=#VpS90p?51T&KnmB`aEUSo1L`yGXW26Q7mfoMkE*jN{@P zqcx|^ahkhZ#R~4rI$>$W`3ukk(lHobDfcWO`xNJ?5eW*`A>Se@cdc3)4j8&y0W3#LtR?TOX za`$K-TYkQX(I!o6;W06v%d#*c5&TI6=R@k;U0Tr?D2tt{1#>TRaA@`-UL6aUP$-u# z(x%SJ0M`~$a836SOzEsP8sz25i;s=jl|t-mQm_A58IPOK+v6yC|9Gvx{>{7TMT=t?Iz)$Ni zIHXj3mS|IEg*wQkrQGyq22zd0nFsA|GXtqUG!{F3*eQKV)^m=y$94}x5jpMn&dEG1 zBs;kXPkNZwlDC&IbXy14y^0&7%!9IzEYZ$BGju#JOFXP!rizfE5Ez>i4258kU%)1> z6@JN{)Sqgkb@EDc_0)+2%SPLhi6;Z{o^ zX|!5SyMWJ*02i&6g$gHuv#*nN7m$x~z+oweIW5c>w=KIsbJ(hsIou=i#Rb}mnE?}M zEiw-4H<+;$afvGXD;U0JHl4z6gewX=L)iJRyuJ

    H4MG1fNW}lDiM<*G@6?IN79GU}HCp1bofd&yDV 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%0D#7NH{5*m6hqyuPQG$bl8G-rr^ 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 Jluy^`{|iGpW1av2 diff --git a/TMessagesProj/src/main/java/org/telegram/android/ContactsController.java b/TMessagesProj/src/main/java/org/telegram/android/ContactsController.java index c5dfd57b..d6f71a5c 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/ContactsController.java +++ b/TMessagesProj/src/main/java/org/telegram/android/ContactsController.java @@ -236,7 +236,7 @@ public class ContactsController { ContentResolver cr = ApplicationLoader.applicationContext.getContentResolver(); HashMap shortContacts = new HashMap(); - String ids = ""; + StringBuilder ids = new StringBuilder(); Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projectionPhones, null, null, null); if (pCur != null) { if (pCur.getCount() > 0) { @@ -262,9 +262,9 @@ public class ContactsController { Integer id = pCur.getInt(0); if (ids.length() != 0) { - ids += ","; + ids.append(","); } - ids += id; + ids.append(id); int type = pCur.getInt(2); Contact contact = contactsMap.get(id); @@ -299,7 +299,7 @@ public class ContactsController { pCur.close(); } - pCur = cr.query(ContactsContract.Data.CONTENT_URI, projectionNames, ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " IN (" + ids + ") AND " + ContactsContract.Data.MIMETYPE + " = '" + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE + "'", null, null); + pCur = cr.query(ContactsContract.Data.CONTENT_URI, projectionNames, ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " IN (" + ids.toString() + ") AND " + ContactsContract.Data.MIMETYPE + " = '" + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE + "'", null, null); if (pCur != null && pCur.getCount() > 0) { while (pCur.moveToNext()) { int id = pCur.getInt(0); @@ -844,14 +844,14 @@ public class ContactsController { return 0; } }); - String ids = ""; + StringBuilder ids = new StringBuilder(); for (TLRPC.TL_contact aContactsArr : contactsArr) { if (ids.length() != 0) { - ids += ","; + ids.append(","); } - ids += aContactsArr.user_id; + ids.append(aContactsArr.user_id); } - UserConfig.contactsHash = Utilities.MD5(ids); + UserConfig.contactsHash = Utilities.MD5(ids.toString()); UserConfig.saveConfig(false); } @@ -1084,7 +1084,7 @@ public class ContactsController { }); } - String ids = ""; + StringBuilder ids = new StringBuilder(); final HashMap> sectionsDict = new HashMap>(); final ArrayList sortedSectionsArray = new ArrayList(); @@ -1114,11 +1114,11 @@ public class ContactsController { } arr.add(value); if (ids.length() != 0) { - ids += ","; + ids.append(","); } - ids += value.user_id; + ids.append(value.user_id); } - UserConfig.contactsHash = Utilities.MD5(ids); + UserConfig.contactsHash = Utilities.MD5(ids.toString()); UserConfig.saveConfig(false); Collections.sort(sortedSectionsArray, new Comparator() { @@ -1189,8 +1189,8 @@ public class ContactsController { } FileLog.e("tmessages", "process update - contacts add = " + newC.size() + " delete = " + contactsTD.size()); - String toAdd = ""; - String toDelete = ""; + StringBuilder toAdd = new StringBuilder(); + StringBuilder toDelete = new StringBuilder(); boolean reloadContacts = false; for (TLRPC.TL_contact newContact : newC) { @@ -1216,9 +1216,9 @@ public class ContactsController { } } if (toAdd.length() != 0) { - toAdd += ","; + toAdd.append(","); } - toAdd += user.phone; + toAdd.append(user.phone); } for (final Integer uid : contactsTD) { @@ -1252,14 +1252,14 @@ public class ContactsController { } } if (toDelete.length() != 0) { - toDelete += ","; + toDelete.append(","); } - toDelete += user.phone; + toDelete.append(user.phone); } } if (toAdd.length() != 0 || toDelete.length() != 0) { - MessagesStorage.getInstance().applyPhoneBookUpdates(toAdd, toDelete); + MessagesStorage.getInstance().applyPhoneBookUpdates(toAdd.toString(), toDelete.toString()); } if (reloadContacts) { diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java index ba6cd5cc..8908da7b 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java @@ -69,7 +69,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter private boolean gettingNewDeleteTask = false; private int currentDeletingTaskTime = 0; - private Long currentDeletingTask = null; private ArrayList currentDeletingTaskMids = null; public int totalDialogsCount = 0; @@ -322,7 +321,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter currentDeletingTaskTime = 0; currentDeletingTaskMids = null; gettingNewDeleteTask = false; - currentDeletingTask = null; loadingDialogs = false; dialogsEndReached = false; gettingDifference = false; @@ -508,14 +506,14 @@ public class MessagesController implements NotificationCenter.NotificationCenter Utilities.stageQueue.postRunnable(new Runnable() { @Override public void run() { - if (currentDeletingTask == null && !gettingNewDeleteTask || currentDeletingTaskTime != 0 && minDate < currentDeletingTaskTime) { + if (currentDeletingTaskMids == null && !gettingNewDeleteTask || currentDeletingTaskTime != 0 && minDate < currentDeletingTaskTime) { getNewDeleteTask(null); } } }); } - public void getNewDeleteTask(final Long oldTask) { + public void getNewDeleteTask(final ArrayList oldTask) { Utilities.stageQueue.postRunnable(new Runnable() { @Override public void run() { @@ -528,7 +526,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter private void checkDeletingTask() { int currentServerTime = ConnectionsManager.getInstance().getCurrentTime(); - if (currentDeletingTask != null && currentDeletingTaskTime != 0 && currentDeletingTaskTime <= currentServerTime) { + if (currentDeletingTaskMids != null && currentDeletingTaskTime != 0 && currentDeletingTaskTime <= currentServerTime) { currentDeletingTaskTime = 0; AndroidUtilities.RunOnUIThread(new Runnable() { @Override @@ -538,9 +536,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter Utilities.stageQueue.postRunnable(new Runnable() { @Override public void run() { - getNewDeleteTask(currentDeletingTask); + getNewDeleteTask(currentDeletingTaskMids); currentDeletingTaskTime = 0; - currentDeletingTask = null; + currentDeletingTaskMids = null; } }); } @@ -548,20 +546,18 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } - public void processLoadedDeleteTask(final Long taskId, final int taskTime, final ArrayList messages) { + public void processLoadedDeleteTask(final int taskTime, final ArrayList messages) { Utilities.stageQueue.postRunnable(new Runnable() { @Override public void run() { gettingNewDeleteTask = false; - if (taskId != null) { + if (messages != null) { currentDeletingTaskTime = taskTime; - currentDeletingTask = taskId; currentDeletingTaskMids = messages; checkDeletingTask(); } else { currentDeletingTaskTime = 0; - currentDeletingTask = null; currentDeletingTaskMids = null; } } @@ -1275,10 +1271,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } - public void loadMessages(final long dialog_id, final int count, final int max_id, boolean fromCache, int midDate, final int classGuid, boolean from_unread, boolean forward) { + public void loadMessages(final long dialog_id, final int count, final int max_id, boolean fromCache, int midDate, final int classGuid, boolean from_unread, boolean forward, final Semaphore semaphore) { int lower_part = (int)dialog_id; if (fromCache || lower_part == 0) { - MessagesStorage.getInstance().getMessages(dialog_id, count, max_id, midDate, classGuid, from_unread, forward); + MessagesStorage.getInstance().getMessages(dialog_id, count, max_id, midDate, classGuid, from_unread, forward, semaphore); } else { TLRPC.TL_messages_getHistory req = new TLRPC.TL_messages_getHistory(); if (lower_part < 0) { @@ -1303,7 +1299,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter public void run(TLObject response, TLRPC.TL_error error) { if (error == null) { final TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; - processLoadedMessages(res, dialog_id, count, max_id, false, classGuid, 0, 0, 0, 0, false); + processLoadedMessages(res, dialog_id, count, max_id, false, classGuid, 0, 0, 0, 0, false, semaphore); } } }); @@ -1311,7 +1307,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } - public void processLoadedMessages(final TLRPC.messages_Messages messagesRes, final long dialog_id, final int count, final int max_id, final boolean isCache, final int classGuid, final int first_unread, final int last_unread, final int unread_count, final int last_date, final boolean isForward) { + public void processLoadedMessages(final TLRPC.messages_Messages messagesRes, final long dialog_id, final int count, final int max_id, final boolean isCache, final int classGuid, final int first_unread, final int last_unread, final int unread_count, final int last_date, final boolean isForward, final Semaphore semaphore) { Utilities.stageQueue.postRunnable(new Runnable() { @Override public void run() { @@ -1320,10 +1316,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter MessagesStorage.getInstance().putMessages(messagesRes, dialog_id); } if (lower_id != 0 && isCache && messagesRes.messages.size() == 0 && !isForward) { + if (semaphore != null) { + semaphore.release(); + } AndroidUtilities.RunOnUIThread(new Runnable() { @Override public void run() { - loadMessages(dialog_id, count, max_id, false, 0, classGuid, false, false); + loadMessages(dialog_id, count, max_id, false, 0, classGuid, false, false, null); } }); return; @@ -1337,14 +1336,21 @@ public class MessagesController implements NotificationCenter.NotificationCenter message.dialog_id = dialog_id; objects.add(new MessageObject(message, usersLocal, 2)); } - AndroidUtilities.RunOnUIThread(new Runnable() { - @Override - public void run() { - putUsers(messagesRes.users, isCache); - putChats(messagesRes.chats, isCache); - NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesDidLoaded, dialog_id, count, objects, isCache, first_unread, last_unread, unread_count, last_date, isForward); - } - }); + if (semaphore != null) { + putUsers(messagesRes.users, isCache); + putChats(messagesRes.chats, isCache); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesDidLoaded, dialog_id, count, objects, isCache, first_unread, last_unread, unread_count, last_date, isForward); + semaphore.release(); + } else { + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + putUsers(messagesRes.users, isCache); + putChats(messagesRes.chats, isCache); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesDidLoaded, dialog_id, count, objects, isCache, first_unread, last_unread, unread_count, last_date, isForward); + } + }); + } } }); } diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java index 9661cc6e..5283acb0 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java @@ -11,6 +11,7 @@ package org.telegram.android; import android.content.Context; import android.content.SharedPreferences; import android.text.Html; +import android.text.TextUtils; import android.util.SparseArray; import org.telegram.PhoneFormat.PhoneFormat; @@ -90,7 +91,7 @@ public class MessagesStorage { database.executeFast("PRAGMA temp_store = 1").stepThis().dispose(); if (createTable) { database.executeFast("CREATE TABLE users(uid INTEGER PRIMARY KEY, name TEXT, status INTEGER, data BLOB)").stepThis().dispose(); - database.executeFast("CREATE TABLE messages(mid INTEGER PRIMARY KEY, uid INTEGER, read_state INTEGER, send_state INTEGER, date INTEGER, data BLOB, out INTEGER, ttl INTEGER)").stepThis().dispose(); + database.executeFast("CREATE TABLE messages(mid INTEGER PRIMARY KEY, uid INTEGER, read_state INTEGER, send_state INTEGER, date INTEGER, data BLOB, out INTEGER, ttl INTEGER, media INTEGER)").stepThis().dispose(); database.executeFast("CREATE TABLE chats(uid INTEGER PRIMARY KEY, name TEXT, data BLOB)").stepThis().dispose(); database.executeFast("CREATE TABLE enc_chats(uid INTEGER PRIMARY KEY, user INTEGER, name TEXT, data BLOB, g BLOB, authkey BLOB, ttl INTEGER)").stepThis().dispose(); database.executeFast("CREATE TABLE dialogs(did INTEGER PRIMARY KEY, date INTEGER, unread_count INTEGER, last_mid INTEGER)").stepThis().dispose(); @@ -101,7 +102,7 @@ public class MessagesStorage { database.executeFast("CREATE TABLE media_counts(uid INTEGER PRIMARY KEY, count INTEGER)").stepThis().dispose(); database.executeFast("CREATE TABLE wallpapers(uid INTEGER PRIMARY KEY, data BLOB)").stepThis().dispose(); database.executeFast("CREATE TABLE randoms(random_id INTEGER PRIMARY KEY, mid INTEGER)").stepThis().dispose(); - database.executeFast("CREATE TABLE enc_tasks(date INTEGER, data BLOB)").stepThis().dispose(); + database.executeFast("CREATE TABLE enc_tasks_v2(mid INTEGER PRIMARY KEY, date INTEGER)").stepThis().dispose(); database.executeFast("CREATE TABLE params(id INTEGER PRIMARY KEY, seq INTEGER, pts INTEGER, date INTEGER, qts INTEGER, lsv INTEGER, sg INTEGER, pbytes BLOB)").stepThis().dispose(); database.executeFast("INSERT INTO params VALUES(1, 0, 0, 0, 0, 0, 0, NULL)").stepThis().dispose(); database.executeFast("CREATE TABLE user_photos(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose(); @@ -122,7 +123,7 @@ public class MessagesStorage { database.executeFast("CREATE INDEX IF NOT EXISTS sphone_deleted_idx_user_phones ON user_phones_v6(sphone, deleted);").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS date_idx_dialogs ON dialogs(date);").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS date_idx_enc_tasks ON enc_tasks(date);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS date_idx_enc_tasks_v2 ON enc_tasks_v2(date);").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS last_mid_idx_dialogs ON dialogs(last_mid);").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS unread_count_idx_dialogs ON dialogs(unread_count);").stepThis().dispose(); @@ -135,7 +136,7 @@ public class MessagesStorage { database.executeFast("CREATE INDEX IF NOT EXISTS mid_out_idx_messages ON messages(mid, out);").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS task_idx_messages ON messages(uid, out, read_state, ttl, date, send_state);").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS send_state_idx_messages ON messages(mid, send_state, date) WHERE mid < 0 AND send_state = 1;").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 4").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 6").stepThis().dispose(); } else { try { SQLiteCursor cursor = database.queryFinalized("SELECT seq, pts, date, qts, lsv, sg, pbytes FROM params WHERE id = 1"); @@ -167,8 +168,8 @@ public class MessagesStorage { } int version = database.executeInt("PRAGMA user_version"); - if (version < 4) { - updateDbToVersion4(); + if (version < 6) { + updateDbToLastVersion(version); } } } catch (Exception e) { @@ -177,82 +178,113 @@ public class MessagesStorage { loadUnreadMessages(); } - public void updateDbToVersion4() { + public void updateDbToLastVersion(final int currentVersion) { storageQueue.postRunnable(new Runnable() { @Override public void run() { try { - database.executeFast("CREATE TABLE IF NOT EXISTS user_photos(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose(); + if (currentVersion < 4) { + database.executeFast("CREATE TABLE IF NOT EXISTS user_photos(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS mid_idx_media ON media(mid);").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS uid_date_mid_idx_media ON media(uid, date, mid);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS mid_idx_media ON media(mid);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_date_mid_idx_media ON media(uid, date, mid);").stepThis().dispose(); - database.executeFast("DROP INDEX IF EXISTS read_state_out_idx_messages;").stepThis().dispose(); - database.executeFast("DROP INDEX IF EXISTS ttl_idx_messages;").stepThis().dispose(); - database.executeFast("DROP INDEX IF EXISTS date_idx_messages;").stepThis().dispose(); + database.executeFast("DROP INDEX IF EXISTS read_state_out_idx_messages;").stepThis().dispose(); + database.executeFast("DROP INDEX IF EXISTS ttl_idx_messages;").stepThis().dispose(); + database.executeFast("DROP INDEX IF EXISTS date_idx_messages;").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS mid_out_idx_messages ON messages(mid, out);").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS task_idx_messages ON messages(uid, out, read_state, ttl, date, send_state);").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS uid_date_mid_idx_messages ON messages(uid, date, mid);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS mid_out_idx_messages ON messages(mid, out);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS task_idx_messages ON messages(uid, out, read_state, ttl, date, send_state);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_date_mid_idx_messages ON messages(uid, date, mid);").stepThis().dispose(); - database.executeFast("CREATE TABLE IF NOT EXISTS user_contacts_v6(uid INTEGER PRIMARY KEY, fname TEXT, sname TEXT)").stepThis().dispose(); - database.executeFast("CREATE TABLE IF NOT EXISTS user_phones_v6(uid INTEGER, phone TEXT, sphone TEXT, deleted INTEGER, PRIMARY KEY (uid, phone))").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS sphone_deleted_idx_user_phones ON user_phones_v6(sphone, deleted);").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS user_contacts_v6(uid INTEGER PRIMARY KEY, fname TEXT, sname TEXT)").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS user_phones_v6(uid INTEGER, phone TEXT, sphone TEXT, deleted INTEGER, PRIMARY KEY (uid, phone))").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS sphone_deleted_idx_user_phones ON user_phones_v6(sphone, deleted);").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS mid_idx_randoms ON randoms(mid);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS mid_idx_randoms ON randoms(mid);").stepThis().dispose(); - database.executeFast("CREATE TABLE IF NOT EXISTS sent_files_v2(uid TEXT, type INTEGER, data BLOB, PRIMARY KEY (uid, type))").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS sent_files_v2(uid TEXT, type INTEGER, data BLOB, PRIMARY KEY (uid, type))").stepThis().dispose(); - database.executeFast("CREATE TABLE IF NOT EXISTS blocked_users(uid INTEGER PRIMARY KEY)").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS blocked_users(uid INTEGER PRIMARY KEY)").stepThis().dispose(); - database.executeFast("CREATE TABLE IF NOT EXISTS download_queue(uid INTEGER, type INTEGER, date INTEGER, data BLOB, PRIMARY KEY (uid, type));").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS type_date_idx_download_queue ON download_queue(type, date);").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS download_queue(uid INTEGER, type INTEGER, date INTEGER, data BLOB, PRIMARY KEY (uid, type));").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS type_date_idx_download_queue ON download_queue(type, date);").stepThis().dispose(); - database.executeFast("CREATE TABLE IF NOT EXISTS dialog_settings(did INTEGER PRIMARY KEY, flags INTEGER);").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS dialog_settings(did INTEGER PRIMARY KEY, flags INTEGER);").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS send_state_idx_messages ON messages(mid, send_state, date) WHERE mid < 0 AND send_state = 1;").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS send_state_idx_messages ON messages(mid, send_state, date) WHERE mid < 0 AND send_state = 1;").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS unread_count_idx_dialogs ON dialogs(unread_count);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS unread_count_idx_dialogs ON dialogs(unread_count);").stepThis().dispose(); - database.executeFast("UPDATE messages SET send_state = 2 WHERE mid < 0 AND send_state = 1").stepThis().dispose(); + database.executeFast("UPDATE messages SET send_state = 2 WHERE mid < 0 AND send_state = 1").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 4").stepThis().dispose(); - storageQueue.postRunnable(new Runnable() { - @Override - public void run() { - ArrayList ids = new ArrayList(); - SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE); - Map values = preferences.getAll(); - for (Map.Entry entry : values.entrySet()) { - String key = entry.getKey(); - if (key.startsWith("notify2_")) { - Integer value = (Integer)entry.getValue(); - if (value == 2) { - key = key.replace("notify2_", ""); - try { - ids.add(Integer.parseInt(key)); - } catch (Exception e) { - e.printStackTrace(); + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + ArrayList ids = new ArrayList(); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE); + Map values = preferences.getAll(); + for (Map.Entry entry : values.entrySet()) { + String key = entry.getKey(); + if (key.startsWith("notify2_")) { + Integer value = (Integer) entry.getValue(); + if (value == 2) { + key = key.replace("notify2_", ""); + try { + ids.add(Integer.parseInt(key)); + } catch (Exception e) { + e.printStackTrace(); + } } } } + try { + database.beginTransaction(); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO dialog_settings VALUES(?, ?)"); + for (Integer id : ids) { + state.requery(); + state.bindLong(1, id); + state.bindInteger(2, 1); + state.step(); + } + state.dispose(); + database.commitTransaction(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } } - try { - database.beginTransaction(); - SQLitePreparedStatement state = database.executeFast("REPLACE INTO dialog_settings VALUES(?, ?)"); - for (Integer id : ids) { + }); + } + if (currentVersion < 6) { + database.executeFast("CREATE TABLE IF NOT EXISTS enc_tasks_v2(mid INTEGER PRIMARY KEY, date INTEGER)").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS date_idx_enc_tasks_v2 ON enc_tasks_v2(date);").stepThis().dispose(); + database.beginTransaction(); + SQLiteCursor cursor = database.queryFinalized("SELECT date, data FROM enc_tasks WHERE 1"); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_tasks_v2 VALUES(?, ?)"); + if (cursor.next()) { + int date = cursor.intValue(0); + int length = 0; + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(1)); + if ((length = cursor.byteBufferValue(1, data.buffer)) != 0) { + for (int a = 0; a < length / 4; a++) { state.requery(); - state.bindLong(1, id); - state.bindInteger(2, 1); + state.bindInteger(1, data.readInt32()); + state.bindInteger(2, date); state.step(); } - state.dispose(); - database.commitTransaction(); - } catch (Exception e) { - FileLog.e("tmessages", e); } + buffersStorage.reuseFreeBuffer(data); } - }); + state.dispose(); + cursor.dispose(); + database.commitTransaction(); + + database.executeFast("DROP INDEX IF EXISTS date_idx_enc_tasks;").stepThis().dispose(); + database.executeFast("DROP TABLE IF EXISTS enc_tasks;").stepThis().dispose(); + + database.executeFast("ALTER TABLE messages ADD COLUMN media INTEGER").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 6").stepThis().dispose(); + } } catch (Exception e) { FileLog.e("tmessages", e); } @@ -368,16 +400,16 @@ public class MessagesStorage { try { final HashMap pushDialogs = new HashMap(); SQLiteCursor cursor = database.queryFinalized("SELECT d.did, d.unread_count, s.flags FROM dialogs as d LEFT JOIN dialog_settings as s ON d.did = s.did WHERE d.unread_count != 0"); - String ids = ""; + StringBuilder ids = new StringBuilder(); while (cursor.next()) { if (cursor.isNull(2) || cursor.intValue(2) != 1) { long did = cursor.longValue(0); int count = cursor.intValue(1); pushDialogs.put(did, count); if (ids.length() != 0) { - ids += ","; + ids.append(","); } - ids += did; + ids.append(did); } } cursor.dispose(); @@ -391,7 +423,7 @@ public class MessagesStorage { ArrayList chatIds = new ArrayList(); ArrayList encryptedChatIds = new ArrayList(); - cursor = database.queryFinalized("SELECT read_state, data, send_state, mid, date, uid FROM messages WHERE uid IN (" + ids + ") AND out = 0 AND read_state = 0 ORDER BY date DESC LIMIT 50"); + cursor = database.queryFinalized("SELECT read_state, data, send_state, mid, date, uid FROM messages WHERE uid IN (" + ids.toString() + ") AND out = 0 AND read_state = 0 ORDER BY date DESC LIMIT 50"); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(1)); if (data != null && cursor.byteBufferValue(1, data.buffer) != 0) { @@ -449,14 +481,8 @@ public class MessagesStorage { } cursor.dispose(); - String stringToLoad = ""; if (!encryptedChatIds.isEmpty()) { - for (int uid : encryptedChatIds) { - if (stringToLoad.length() != 0) { - stringToLoad += ","; - } - stringToLoad += uid; - } + String stringToLoad = TextUtils.join(",", encryptedChatIds); cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl FROM enc_chats WHERE uid IN(%s)", stringToLoad)); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); @@ -477,13 +503,7 @@ public class MessagesStorage { } if (!userIds.isEmpty()) { - stringToLoad = ""; - for (Integer uid : userIds) { - if (stringToLoad.length() != 0) { - stringToLoad += ","; - } - stringToLoad += uid; - } + String stringToLoad = TextUtils.join(",", userIds); cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", stringToLoad)); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); @@ -500,13 +520,7 @@ public class MessagesStorage { } if (!chatIds.isEmpty()) { - stringToLoad = ""; - for (Integer cid : chatIds) { - if (stringToLoad.length() != 0) { - stringToLoad += ","; - } - stringToLoad += cid; - } + String stringToLoad = TextUtils.join(",", chatIds); cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid IN(%s)", stringToLoad)); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); @@ -593,19 +607,19 @@ public class MessagesStorage { ArrayList ids = new ArrayList(); ArrayList users = new ArrayList(); SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT * FROM blocked_users WHERE 1")); - String usersToLoad = ""; + StringBuilder usersToLoad = new StringBuilder(); while (cursor.next()) { int user_id = cursor.intValue(0); ids.add(user_id); if (usersToLoad.length() != 0) { - usersToLoad += ","; + usersToLoad.append(","); } - usersToLoad += user_id; + usersToLoad.append(user_id); } cursor.dispose(); if (usersToLoad.length() != 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad.toString())); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { @@ -793,34 +807,28 @@ public class MessagesStorage { }); } - public void getNewTask(final Long oldTask) { + public void getNewTask(final ArrayList oldTask) { storageQueue.postRunnable(new Runnable() { @Override public void run() { try { if (oldTask != null) { - database.executeFast("DELETE FROM enc_tasks WHERE rowid = " + oldTask).stepThis().dispose(); + String ids = TextUtils.join(",", oldTask); + database.executeFast(String.format(Locale.US, "DELETE FROM enc_tasks_v2 WHERE mid IN(%s)", ids)).stepThis().dispose(); } - Long taskId = null; int date = 0; ArrayList arr = null; - SQLiteCursor cursor = database.queryFinalized("SELECT rowid, date, data FROM enc_tasks ORDER BY date ASC LIMIT 1"); - if (cursor.next()) { - taskId = cursor.longValue(0); + SQLiteCursor cursor = database.queryFinalized("SELECT mid, date FROM enc_tasks_v2 WHERE date = (SELECT min(date) FROM enc_tasks_v2)"); + while (cursor.next()) { + Integer mid = cursor.intValue(0); date = cursor.intValue(1); - - int length = 0; - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(2)); - if ((length = cursor.byteBufferValue(2, data.buffer)) != 0) { + if (arr == null) { arr = new ArrayList(); - for (int a = 0; a < length / 4; a++) { - arr.add(data.readInt32()); - } } - buffersStorage.reuseFreeBuffer(data); + arr.add(mid); } cursor.dispose(); - MessagesController.getInstance().processLoadedDeleteTask(taskId, date, arr); + MessagesController.getInstance().processLoadedDeleteTask(date, arr); } catch (Exception e) { FileLog.e("tmessages", e); } @@ -835,13 +843,11 @@ public class MessagesStorage { try { int minDate = Integer.MAX_VALUE; SparseArray> messages = new SparseArray>(); - String mids = ""; - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid, ttl, read_state FROM messages WHERE uid = %d AND out = %d AND ttl > 0 AND date <= %d AND send_state = 0", ((long)chat_id) << 32, isOut, time)); + StringBuilder mids = new StringBuilder(); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid, ttl FROM messages WHERE uid = %d AND out = %d AND read_state = 1 AND ttl > 0 AND date <= %d AND send_state = 0 AND media != 1", ((long)chat_id) << 32, isOut, time)); while (cursor.next()) { int mid = cursor.intValue(0); - int ttl = cursor.intValue(1); - int read_state = cursor.intValue(2); - int date = readTime + ttl; + int date = readTime + cursor.intValue(1); minDate = Math.min(minDate, date); ArrayList arr = messages.get(date); if (arr == null) { @@ -849,38 +855,28 @@ public class MessagesStorage { messages.put(date, arr); } if (mids.length() != 0) { - mids += ","; + mids.append(","); } - mids += "" + mid; + mids.append(mid); arr.add(mid); } cursor.dispose(); if (messages.size() != 0) { database.beginTransaction(); - SQLitePreparedStatement state = database.executeFast("INSERT INTO enc_tasks VALUES(?, ?)"); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_tasks_v2 VALUES(?, ?)"); for (int a = 0; a < messages.size(); a++) { int key = messages.keyAt(a); ArrayList arr = messages.get(key); - ByteBufferDesc data = buffersStorage.getFreeBuffer(404); - int count = 0; - for (int b = 0; b < arr.size(); b++) { - int mid = arr.get(b); - data.writeInt32(mid); - count++; - if (b == arr.size() - 1 || b != 0 && b % 100 == 0) { - state.requery(); - data.limit(count * 4); - state.bindInteger(1, key); - state.bindByteBuffer(2, data.buffer); - state.step(); - count = 0; - } + for (Integer mid : arr) { + state.requery(); + state.bindInteger(1, mid); + state.bindInteger(2, key); + state.step(); } - buffersStorage.reuseFreeBuffer(data); } state.dispose(); database.commitTransaction(); - database.executeFast(String.format(Locale.US, "UPDATE messages SET ttl = 0 WHERE mid IN(%s)", mids)).stepThis().dispose(); + database.executeFast(String.format(Locale.US, "UPDATE messages SET ttl = 0 WHERE mid IN(%s)", mids.toString())).stepThis().dispose(); MessagesController.getInstance().didAddedNewTask(minDate); } } catch (Exception e) { @@ -896,15 +892,9 @@ public class MessagesStorage { } try { HashMap dialogsToUpdate = new HashMap(); - String dialogsToReload = ""; if (messages != null && !messages.isEmpty()) { - String ids = ""; - for (int uid : messages) { - if (ids.length() != 0) { - ids += ","; - } - ids += uid; - } + StringBuilder dialogsToReload = new StringBuilder(); + String ids = TextUtils.join(",", messages); int totalCount = 0; SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT uid, read_state, out FROM messages WHERE mid IN(%s)", ids)); while (cursor.next()) { @@ -922,20 +912,16 @@ public class MessagesStorage { if (currentCount == null) { dialogsToUpdate.put(uid, 1); if (dialogsToReload.length() != 0) { - dialogsToReload += ","; + dialogsToReload.append(","); } - dialogsToReload += uid; + dialogsToReload.append(uid); } else { dialogsToUpdate.put(uid, currentCount + 1); } } cursor.dispose(); - if (totalCount != messages.size()) { - FileLog.e("tmessages", "messages read mismatch!"); - } - - cursor = database.queryFinalized(String.format(Locale.US, "SELECT did, unread_count FROM dialogs WHERE did IN(%s)", dialogsToReload)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT did, unread_count FROM dialogs WHERE did IN(%s)", dialogsToReload.toString())); while (cursor.next()) { long did = cursor.longValue(0); int count = cursor.intValue(1); @@ -1098,7 +1084,7 @@ public class MessagesStorage { if (info != null) { boolean modified = false; ArrayList usersArr = new ArrayList(); - String usersToLoad = ""; + StringBuilder usersToLoad = new StringBuilder(); for (int a = 0; a < info.participants.size(); a++) { TLRPC.TL_chatParticipant c = info.participants.get(a); if (usersArr.contains(c.user_id)) { @@ -1107,14 +1093,14 @@ public class MessagesStorage { a--; } else { if (usersToLoad.length() != 0) { - usersToLoad += ","; + usersToLoad.append(","); } usersArr.add(c.user_id); - usersToLoad += c.user_id; + usersToLoad.append(c.user_id); } } if (usersToLoad.length() != 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad.toString())); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { @@ -1322,13 +1308,7 @@ public class MessagesStorage { @Override public void run() { try { - String ids = ""; - for (Integer uid : uids) { - if (ids.length() != 0) { - ids += ","; - } - ids += "" + uid; - } + String ids = TextUtils.join(",", uids); database.executeFast("DELETE FROM contacts WHERE uid IN(" + ids + ")").stepThis().dispose(); } catch (Exception e) { FileLog.e("tmessages", e); @@ -1446,7 +1426,7 @@ public class MessagesStorage { ArrayList users = new ArrayList(); try { SQLiteCursor cursor = database.queryFinalized("SELECT * FROM contacts WHERE 1"); - String uids = ""; + StringBuilder uids = new StringBuilder(); while (cursor.next()) { int user_id = cursor.intValue(0); if (user_id == UserConfig.getClientUserId()) { @@ -1456,15 +1436,15 @@ public class MessagesStorage { contact.user_id = user_id; contact.mutual = cursor.intValue(1) == 1; if (uids.length() != 0) { - uids += ","; + uids.append(","); } contacts.add(contact); - uids += contact.user_id; + uids.append(contact.user_id); } cursor.dispose(); if (uids.length() != 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", uids)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", uids.toString())); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { @@ -1574,18 +1554,18 @@ public class MessagesStorage { } cursor.dispose(); - String usersToLoad = ""; + StringBuilder usersToLoad = new StringBuilder(); for (int uid : fromUser) { if (!loadedUsers.contains(uid)) { if (usersToLoad.length() != 0) { - usersToLoad += ","; + usersToLoad.append(","); } - usersToLoad += uid; + usersToLoad.append(uid); loadedUsers.add(uid); } } if (usersToLoad.length() != 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad.toString())); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { @@ -1722,14 +1702,9 @@ public class MessagesStorage { } cursor.dispose(); - String stringToLoad = ""; + if (!encryptedChatIds.isEmpty()) { - for (int uid : encryptedChatIds) { - if (stringToLoad.length() != 0) { - stringToLoad += ","; - } - stringToLoad += uid; - } + String stringToLoad = TextUtils.join(",", encryptedChatIds); cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl FROM enc_chats WHERE uid IN(%s)", stringToLoad)); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); @@ -1751,13 +1726,7 @@ public class MessagesStorage { if (!userIds.isEmpty()) { - stringToLoad = ""; - for (Integer uid : userIds) { - if (stringToLoad.length() != 0) { - stringToLoad += ","; - } - stringToLoad += uid; - } + String stringToLoad = TextUtils.join(",", userIds); cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", stringToLoad)); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); @@ -1774,20 +1743,20 @@ public class MessagesStorage { } if (!chatIds.isEmpty() || !broadcastIds.isEmpty()) { - stringToLoad = ""; + StringBuilder stringToLoad = new StringBuilder(); for (Integer cid : chatIds) { if (stringToLoad.length() != 0) { - stringToLoad += ","; + stringToLoad.append(","); } - stringToLoad += cid; + stringToLoad.append(cid); } for (Integer cid : broadcastIds) { if (stringToLoad.length() != 0) { - stringToLoad += ","; + stringToLoad.append(","); } - stringToLoad += (-cid); + stringToLoad.append(-cid); } - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid IN(%s)", stringToLoad)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid IN(%s)", stringToLoad.toString())); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { @@ -1807,7 +1776,7 @@ public class MessagesStorage { }); } - public void getMessages(final long dialog_id, final int count, final int max_id, final int minDate, final int classGuid, final boolean from_unread, final boolean forward) { + public void getMessages(final long dialog_id, final int count, final int max_id, final int minDate, final int classGuid, final boolean from_unread, final boolean forward, final Semaphore semaphore) { storageQueue.postRunnable(new Runnable() { @Override public void run() { @@ -1991,18 +1960,18 @@ public class MessagesStorage { } cursor.dispose(); - String usersToLoad = ""; + StringBuilder usersToLoad = new StringBuilder(); for (int uid : fromUser) { if (!loadedUsers.contains(uid)) { if (usersToLoad.length() != 0) { - usersToLoad += ","; + usersToLoad.append(","); } - usersToLoad += uid; + usersToLoad.append(uid); loadedUsers.add(uid); } } if (usersToLoad.length() != 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad.toString())); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { @@ -2023,7 +1992,7 @@ public class MessagesStorage { res.users.clear(); FileLog.e("tmessages", e); } finally { - MessagesController.getInstance().processLoadedMessages(res, dialog_id, count_query, max_id, true, classGuid, min_unread_id, max_unread_id, count_unread, max_unread_date, forward); + MessagesController.getInstance().processLoadedMessages(res, dialog_id, count_query, max_id, true, classGuid, min_unread_id, max_unread_id, count_unread, max_unread_date, forward, semaphore); } } }); @@ -2448,6 +2417,18 @@ public class MessagesStorage { }); } + private int getMessageMediaType(TLRPC.Message message) { + if (message.media == null) { + return 0; + } else if (message.media instanceof TLRPC.TL_messageMediaPhoto) { + return 1; + } else if (message.media instanceof TLRPC.TL_messageMediaVideo) { + return 2; + } else { + return 0; + } + } + private void putMessagesInternal(final ArrayList messages, final boolean withTransaction, final boolean isBroadcast, final int downloadMask) { try { if (withTransaction) { @@ -2458,9 +2439,9 @@ public class MessagesStorage { HashMap mediaCounts = new HashMap(); HashMap messagesIdsMap = new HashMap(); HashMap messagesMediaIdsMap = new HashMap(); - String messageIds = ""; - String messageMediaIds = ""; - SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages VALUES(?, ?, ?, ?, ?, ?, ?, ?)"); + StringBuilder messageIds = new StringBuilder(); + StringBuilder messageMediaIds = new StringBuilder(); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)"); SQLitePreparedStatement state2 = database.executeFast("REPLACE INTO media VALUES(?, ?, ?, ?)"); SQLitePreparedStatement state3 = database.executeFast("REPLACE INTO randoms VALUES(?, ?)"); SQLitePreparedStatement state4 = database.executeFast("REPLACE INTO download_queue VALUES(?, ?, ?, ?)"); @@ -2477,23 +2458,23 @@ public class MessagesStorage { if (message.unread && !message.out) { if (messageIds.length() > 0) { - messageIds += ","; + messageIds.append(","); } - messageIds += message.id; + messageIds.append(message.id); messagesIdsMap.put(message.id, dialog_id); } - if (message.media instanceof TLRPC.TL_messageMediaVideo || message.media instanceof TLRPC.TL_messageMediaPhoto) { + if (message.ttl == 0 && (message.media instanceof TLRPC.TL_messageMediaVideo || message.media instanceof TLRPC.TL_messageMediaPhoto)) { if (messageMediaIds.length() > 0) { - messageMediaIds += ","; + messageMediaIds.append(","); } - messageMediaIds += message.id; + messageMediaIds.append(message.id); messagesMediaIdsMap.put(message.id, dialog_id); } } if (messageIds.length() > 0) { - SQLiteCursor cursor = database.queryFinalized("SELECT mid FROM messages WHERE mid IN(" + messageIds + ")"); + SQLiteCursor cursor = database.queryFinalized("SELECT mid FROM messages WHERE mid IN(" + messageIds.toString() + ")"); while (cursor.next()) { int mid = cursor.intValue(0); messagesIdsMap.remove(mid); @@ -2510,7 +2491,7 @@ public class MessagesStorage { } if (messageMediaIds.length() > 0) { - SQLiteCursor cursor = database.queryFinalized("SELECT mid FROM media WHERE mid IN(" + messageMediaIds + ")"); + SQLiteCursor cursor = database.queryFinalized("SELECT mid FROM media WHERE mid IN(" + messageMediaIds.toString() + ")"); while (cursor.next()) { int mid = cursor.intValue(0); messagesMediaIdsMap.remove(mid); @@ -2557,6 +2538,7 @@ public class MessagesStorage { state.bindByteBuffer(6, data.buffer); state.bindInteger(7, (message.out ? 1 : 0)); state.bindInteger(8, message.ttl); + state.bindInteger(9, getMessageMediaType(message)); state.step(); if (message.random_id != 0) { @@ -2566,7 +2548,7 @@ public class MessagesStorage { state3.step(); } - if (message.media instanceof TLRPC.TL_messageMediaVideo || message.media instanceof TLRPC.TL_messageMediaPhoto) { + if (message.ttl == 0 && (message.media instanceof TLRPC.TL_messageMediaVideo || message.media instanceof TLRPC.TL_messageMediaPhoto)) { state2.requery(); state2.bindInteger(1, messageId); state2.bindLong(2, dialog_id); @@ -2862,17 +2844,17 @@ public class MessagesStorage { database.commitTransaction(); } } else { - String ids = ""; + StringBuilder ids = new StringBuilder(); HashMap usersDict = new HashMap(); for (TLRPC.User user : users) { if (ids.length() != 0) { - ids += ","; + ids.append(","); } - ids += user.id; + ids.append(user.id); usersDict.put(user.id, user); } ArrayList loadedUsers = new ArrayList(); - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", ids)); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", ids.toString())); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { @@ -2950,13 +2932,7 @@ public class MessagesStorage { } try { if (messages != null && !messages.isEmpty()) { - String ids = ""; - for (int uid : messages) { - if (ids.length() != 0) { - ids += ","; - } - ids += uid; - } + String ids = TextUtils.join(",", messages); database.executeFast(String.format(Locale.US, "UPDATE messages SET read_state = 1 WHERE mid IN(%s)", ids)).stepThis().dispose(); } if (encryptedMessages != null && !encryptedMessages.isEmpty()) { @@ -2997,13 +2973,7 @@ public class MessagesStorage { @Override public void run() { try { - String ids = ""; - for (long uid : messages) { - if (ids.length() != 0) { - ids += ","; - } - ids += uid; - } + String ids = TextUtils.join(",", messages); SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid FROM randoms WHERE random_id IN(%s)", ids)); final ArrayList mids = new ArrayList(); while (cursor.next()) { @@ -3038,13 +3008,7 @@ public class MessagesStorage { throw new RuntimeException("wrong db thread"); } try { - String ids = ""; - for (int uid : messages) { - if (ids.length() != 0) { - ids += ","; - } - ids += uid; - } + String ids = TextUtils.join(",", messages); database.executeFast(String.format(Locale.US, "DELETE FROM messages WHERE mid IN(%s)", ids)).stepThis().dispose(); database.executeFast(String.format(Locale.US, "DELETE FROM media WHERE mid IN(%s)", ids)).stepThis().dispose(); database.executeFast("DELETE FROM media_counts WHERE 1").stepThis().dispose(); @@ -3059,13 +3023,7 @@ public class MessagesStorage { throw new RuntimeException("wrong db thread"); } try { - String ids = ""; - for (int uid : messages) { - if (ids.length() != 0) { - ids += ","; - } - ids += uid; - } + String ids = TextUtils.join(",", messages); SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT did FROM dialogs WHERE last_mid IN(%s)", ids)); ArrayList dialogsToUpdate = new ArrayList(); while (cursor.next()) { @@ -3084,13 +3042,7 @@ public class MessagesStorage { state.dispose(); database.commitTransaction(); - ids = ""; - for (long uid : dialogsToUpdate) { - if (ids.length() != 0) { - ids += ","; - } - ids += uid; - } + ids = TextUtils.join(",", dialogsToUpdate); TLRPC.messages_Dialogs dialogs = new TLRPC.messages_Dialogs(); ArrayList encryptedChats = new ArrayList(); @@ -3157,13 +3109,7 @@ public class MessagesStorage { cursor.dispose(); if (!encryptedToLoad.isEmpty()) { - String toLoad = ""; - for (int uid : encryptedToLoad) { - if (toLoad.length() != 0) { - toLoad += ","; - } - toLoad += uid; - } + String toLoad = TextUtils.join(",", encryptedToLoad); cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl FROM enc_chats WHERE uid IN(%s)", toLoad)); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); @@ -3184,13 +3130,7 @@ public class MessagesStorage { } if (!chatsToLoad.isEmpty()) { - String toLoad = ""; - for (int uid : chatsToLoad) { - if (toLoad.length() != 0) { - toLoad += ","; - } - toLoad += uid; - } + String toLoad = TextUtils.join(",", chatsToLoad); cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid IN(%s)", toLoad)); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); @@ -3204,13 +3144,7 @@ public class MessagesStorage { } if (!usersToLoad.isEmpty()) { - String toLoad = ""; - for (int uid : usersToLoad) { - if (toLoad.length() != 0) { - toLoad += ","; - } - toLoad += uid; - } + String toLoad = TextUtils.join(",", usersToLoad); cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", toLoad)); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); @@ -3276,7 +3210,7 @@ public class MessagesStorage { try { database.beginTransaction(); if (!messages.messages.isEmpty()) { - SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages VALUES(?, ?, ?, ?, ?, ?, ?, ?)"); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)"); SQLitePreparedStatement state2 = database.executeFast("REPLACE INTO media VALUES(?, ?, ?, ?)"); for (TLRPC.Message message : messages.messages) { state.requery(); @@ -3290,6 +3224,7 @@ public class MessagesStorage { state.bindByteBuffer(6, data.buffer); state.bindInteger(7, (message.out ? 1 : 0)); state.bindInteger(8, 0); + state.bindInteger(9, getMessageMediaType(message)); state.step(); if (message.media instanceof TLRPC.TL_messageMediaVideo || message.media instanceof TLRPC.TL_messageMediaPhoto) { @@ -3430,13 +3365,7 @@ public class MessagesStorage { cursor.dispose(); if (!encryptedToLoad.isEmpty()) { - String toLoad = ""; - for (int uid : encryptedToLoad) { - if (toLoad.length() != 0) { - toLoad += ","; - } - toLoad += uid; - } + String toLoad = TextUtils.join(",", encryptedToLoad); cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl FROM enc_chats WHERE uid IN(%s)", toLoad)); while (cursor.next()) { try { @@ -3463,13 +3392,7 @@ public class MessagesStorage { } if (!chatsToLoad.isEmpty()) { - String toLoad = ""; - for (int uid : chatsToLoad) { - if (toLoad.length() != 0) { - toLoad += ","; - } - toLoad += uid; - } + String toLoad = TextUtils.join(",", chatsToLoad); cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid IN(%s)", toLoad)); while (cursor.next()) { try { @@ -3489,13 +3412,7 @@ public class MessagesStorage { } if (!usersToLoad.isEmpty()) { - String toLoad = ""; - for (int uid : usersToLoad) { - if (toLoad.length() != 0) { - toLoad += ","; - } - toLoad += uid; - } + String toLoad = TextUtils.join(",", usersToLoad); cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", toLoad)); while (cursor.next()) { try { @@ -3549,7 +3466,7 @@ public class MessagesStorage { } if (!dialogs.dialogs.isEmpty()) { - SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages VALUES(?, ?, ?, ?, ?, ?, ?, ?)"); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)"); SQLitePreparedStatement state2 = database.executeFast("REPLACE INTO dialogs(did, date, unread_count, last_mid) VALUES(?, ?, ?, ?)"); SQLitePreparedStatement state3 = database.executeFast("REPLACE INTO media VALUES(?, ?, ?, ?)"); SQLitePreparedStatement state4 = database.executeFast("REPLACE INTO dialog_settings VALUES(?, ?)"); @@ -3574,6 +3491,7 @@ public class MessagesStorage { state.bindByteBuffer(6, data.buffer); state.bindInteger(7, (message.out ? 1 : 0)); state.bindInteger(8, 0); + state.bindInteger(9, getMessageMediaType(message)); state.step(); state2.bindLong(1, uid); @@ -3683,14 +3601,7 @@ public class MessagesStorage { public ArrayList getUsers(final ArrayList uids, final boolean[] error) { ArrayList users = new ArrayList(); try { - String uidsStr = ""; - - for (Integer uid : uids) { - if (uidsStr.length() != 0) { - uidsStr += ","; - } - uidsStr += uid; - } + String uidsStr = TextUtils.join(",", uids); SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN (%s)", uidsStr)); while (cursor.next()) { diff --git a/TMessagesProj/src/main/java/org/telegram/android/NativeLoader.java b/TMessagesProj/src/main/java/org/telegram/android/NativeLoader.java index 4e66ae6f..c52d3431 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/NativeLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/android/NativeLoader.java @@ -24,9 +24,9 @@ import java.util.zip.ZipFile; public class NativeLoader { private static final long sizes[] = new long[] { - 946908, //armeabi - 1028848, //armeabi-v7a - 1603780, //x86 + 951052, //armeabi + 1032992, //armeabi-v7a + 1612020, //x86 0, //mips }; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java index 11125504..7a6950aa 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java @@ -9000,6 +9000,41 @@ public class TLRPC { } } + public static class TL_message_secret extends TL_message { + public static int constructor = 0x555555F8; + + public void readParams(AbsSerializedData stream) { + id = stream.readInt32(); + from_id = stream.readInt32(); + to_id = (Peer)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); + out = stream.readBool(); + unread = stream.readBool(); + date = stream.readInt32(); + message = stream.readString(); + media = (MessageMedia)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); + if (id < 0 || (media != null && !(media instanceof TL_messageMediaEmpty) && message != null && message.length() != 0 && message.startsWith("-1"))) { + attachPath = stream.readString(); + } + if (id < 0 && message.length() > 6 && media instanceof TL_messageMediaVideo) { + videoEditedInfo = new VideoEditedInfo(); + videoEditedInfo.parseString(message); + } + } + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeInt32(from_id); + to_id.serializeToStream(stream); + stream.writeBool(out); + stream.writeBool(unread); + stream.writeInt32(date); + stream.writeString(message); + media.serializeToStream(stream); + stream.writeString(attachPath); + } + } + public static class TL_messages_deleteMessages extends TLObject { public static int constructor = 0x14f2dd0a; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 8cf9b438..23a55f33 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -117,6 +117,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private TypingDotsDrawable typingDotsDrawable; private View emptyViewContainer; private ArrayList actionModeViews = new ArrayList(); + private Semaphore testSemaphore = new Semaphore(0); private TextView bottomOverlayText; @@ -352,7 +353,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not super.onFragmentCreate(); loading = true; - MessagesController.getInstance().loadMessages(dialog_id, 30, 0, true, 0, classGuid, true, false); + + MessagesController.getInstance().loadMessages(dialog_id, AndroidUtilities.isTablet() ? 30 : 20, 0, true, 0, classGuid, true, false, testSemaphore); + try { + testSemaphore.acquire(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (currentUser != null) { userBlocked = MessagesController.getInstance().blockedUsers.contains(currentUser.id); } @@ -766,16 +774,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (firstVisibleItem <= 4) { if (!endReached && !loading) { if (messagesByDays.size() != 0) { - MessagesController.getInstance().loadMessages(dialog_id, 20, maxMessageId, !cacheEndReaced, minDate, classGuid, false, false); + MessagesController.getInstance().loadMessages(dialog_id, 20, maxMessageId, !cacheEndReaced, minDate, classGuid, false, false, null); } else { - MessagesController.getInstance().loadMessages(dialog_id, 20, 0, !cacheEndReaced, minDate, classGuid, false, false); + MessagesController.getInstance().loadMessages(dialog_id, 20, 0, !cacheEndReaced, minDate, classGuid, false, false, null); } loading = true; } } if (firstVisibleItem + visibleItemCount >= totalItemCount - 6) { if (!unread_end_reached && !loadingForward) { - MessagesController.getInstance().loadMessages(dialog_id, 20, minMessageId, true, maxDate, classGuid, false, true); + MessagesController.getInstance().loadMessages(dialog_id, 20, minMessageId, true, maxDate, classGuid, false, true, null); loadingForward = true; } } @@ -896,7 +904,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not unread_end_reached = true; loading = true; chatAdapter.notifyDataSetChanged(); - MessagesController.getInstance().loadMessages(dialog_id, 30, 0, true, 0, classGuid, true, false); + MessagesController.getInstance().loadMessages(dialog_id, 30, 0, true, 0, classGuid, true, false, null); } } @@ -2249,7 +2257,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } maxDate = Integer.MIN_VALUE; minDate = 0; - MessagesController.getInstance().loadMessages(dialog_id, 30, 0, !cacheEndReaced, minDate, classGuid, false, false); + MessagesController.getInstance().loadMessages(dialog_id, 30, 0, !cacheEndReaced, minDate, classGuid, false, false, null); loading = true; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index c1c13b1b..8140abcd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -2138,7 +2138,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat float ai = -1; if (System.currentTimeMillis() - animationStartTime < animationDuration) { ai = interpolator.getInterpolation((float)(System.currentTimeMillis() - animationStartTime) / animationDuration); - if (ai >= 0.95) { + if (ai >= 0.999f) { ai = -1; } } diff --git a/TMessagesProj/src/main/res/anim/decelerate_cubic.xml b/TMessagesProj/src/main/res/anim/decelerate_cubic.xml new file mode 100644 index 00000000..053d6d20 --- /dev/null +++ b/TMessagesProj/src/main/res/anim/decelerate_cubic.xml @@ -0,0 +1,3 @@ + + diff --git a/TMessagesProj/src/main/res/anim/scale_in.xml b/TMessagesProj/src/main/res/anim/scale_in.xml index 71c2d72d..406fd345 100644 --- a/TMessagesProj/src/main/res/anim/scale_in.xml +++ b/TMessagesProj/src/main/res/anim/scale_in.xml @@ -1,15 +1,31 @@ - + + + + + + + + + + + + + + - + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/anim/scale_out.xml b/TMessagesProj/src/main/res/anim/scale_out.xml index 293099d8..17bd0e7c 100644 --- a/TMessagesProj/src/main/res/anim/scale_out.xml +++ b/TMessagesProj/src/main/res/anim/scale_out.xml @@ -1,16 +1,34 @@ - + + + + + + + + + - + + + + + + + android:interpolator="@anim/decelerate_cubic" + android:duration="220"/> + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable-hdpi/burn.png b/TMessagesProj/src/main/res/drawable-hdpi/burn.png new file mode 100755 index 0000000000000000000000000000000000000000..25833185e6aa7115b8dff49baa16aa146981210e GIT binary patch literal 2824 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 THAZ@l?f1mvMsX_HtG4_D+sxL) literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/burn.png b/TMessagesProj/src/main/res/drawable-mdpi/burn.png new file mode 100755 index 0000000000000000000000000000000000000000..80ed22b3442216550dbb11dd702c656b95373ac2 GIT binary patch literal 2175 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 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/burn.png b/TMessagesProj/src/main/res/drawable-xxhdpi/burn.png new file mode 100755 index 0000000000000000000000000000000000000000..242852251608653201edf081213535fa7143c34d GIT binary patch literal 5245 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 literal 0 HcmV?d00001 From 22a0c2aca644d8f4c41f727a6c16a5401b191249 Mon Sep 17 00:00:00 2001 From: DrKLO Date: Thu, 9 Oct 2014 19:55:05 +0400 Subject: [PATCH 02/18] Fixes (unstable, don't upload to markets) --- TMessagesProj/jni/image.c | 103 ++++++- .../libs/armeabi-v7a/libtmessages.so | Bin 1032992 -> 1041184 bytes TMessagesProj/libs/armeabi/libtmessages.so | Bin 951052 -> 955148 bytes TMessagesProj/libs/x86/libtmessages.so | Bin 1612020 -> 1616116 bytes .../telegram/android/AndroidUtilities.java | 4 + .../org/telegram/android/ImageLoader.java | 3 +- .../org/telegram/android/ImageReceiver.java | 7 +- .../org/telegram/android/MessageObject.java | 60 +++- .../telegram/android/MessagesController.java | 57 ++-- .../org/telegram/android/MessagesStorage.java | 56 ++-- .../org/telegram/android/NativeLoader.java | 6 +- .../org/telegram/android/PhotoObject.java | 10 +- .../telegram/android/SendMessagesHelper.java | 66 ++++- .../messenger/ConnectionsManager.java | 4 + .../org/telegram/messenger/TLClassStore.java | 1 + .../java/org/telegram/messenger/TLRPC.java | 43 ++- .../org/telegram/messenger/Utilities.java | 3 +- .../org/telegram/ui/Cells/ChatMediaCell.java | 89 +++++- .../java/org/telegram/ui/ChatActivity.java | 63 +++- .../java/org/telegram/ui/LaunchActivity.java | 1 + .../org/telegram/ui/SecretPhotoViewer.java | 279 ++++++++++++++++++ .../org/telegram/ui/UserProfileActivity.java | 17 +- .../org/telegram/ui/VideoEditorActivity.java | 27 +- .../src/main/res/drawable-hdpi/burn.png | Bin 2824 -> 2986 bytes .../src/main/res/drawable-hdpi/circle.png | Bin 0 -> 1874 bytes .../src/main/res/drawable-hdpi/photocheck.png | Bin 0 -> 2401 bytes .../src/main/res/drawable-ldpi/burn.png | Bin 1803 -> 1921 bytes .../src/main/res/drawable-ldpi/circle.png | Bin 0 -> 1354 bytes .../src/main/res/drawable-ldpi/photocheck.png | Bin 0 -> 1668 bytes .../src/main/res/drawable-mdpi/burn.png | Bin 2175 -> 2294 bytes .../src/main/res/drawable-mdpi/circle.png | Bin 0 -> 1565 bytes .../src/main/res/drawable-mdpi/photocheck.png | Bin 0 -> 1946 bytes .../src/main/res/drawable-xhdpi/burn.png | Bin 3645 -> 3917 bytes .../src/main/res/drawable-xhdpi/circle.png | Bin 0 -> 2533 bytes .../main/res/drawable-xhdpi/photocheck.png | Bin 0 -> 3086 bytes .../src/main/res/drawable-xxhdpi/burn.png | Bin 5245 -> 5544 bytes .../src/main/res/drawable-xxhdpi/circle.png | Bin 0 -> 3175 bytes .../main/res/drawable-xxhdpi/photocheck.png | Bin 0 -> 4201 bytes 38 files changed, 753 insertions(+), 146 deletions(-) create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/SecretPhotoViewer.java create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/circle.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/photocheck.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/circle.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/photocheck.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/circle.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/photocheck.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/circle.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/photocheck.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/circle.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/photocheck.png diff --git a/TMessagesProj/jni/image.c b/TMessagesProj/jni/image.c index 742bad89..cdd66a47 100644 --- a/TMessagesProj/jni/image.c +++ b/TMessagesProj/jni/image.c @@ -9,12 +9,11 @@ static inline uint64_t get_colors (const uint8_t *p) { return p[0] + (p[1] << 16) + ((uint64_t)p[2] << 32); } -static void fastBlur(int imageWidth, int imageHeight, int imageStride, void *pixels) { +static void fastBlurMore(int imageWidth, int imageHeight, int imageStride, void *pixels, int radius) { uint8_t *pix = (uint8_t *)pixels; const int w = imageWidth; const int h = imageHeight; const int stride = imageStride; - const int radius = 3; const int r1 = radius + 1; const int div = radius * 2 + 1; @@ -23,6 +22,98 @@ static void fastBlur(int imageWidth, int imageHeight, int imageStride, void *pix } uint64_t *rgb = malloc(imageWidth * imageHeight * sizeof(uint64_t)); + if (rgb == NULL) { + return; + } + + int x, y, i; + + int yw = 0; + const int we = w - r1; + for (y = 0; y < h; y++) { + uint64_t cur = get_colors (&pix[yw]); + uint64_t rgballsum = -radius * cur; + uint64_t rgbsum = cur * ((r1 * (r1 + 1)) >> 1); + + for (i = 1; i <= radius; i++) { + uint64_t cur = get_colors (&pix[yw + i * 4]); + rgbsum += cur * (r1 - i); + rgballsum += cur; + } + + x = 0; + + #define update(start, middle, end) \ + rgb[y * w + x] = (rgbsum >> 6) & 0x00FF00FF00FF00FF; \ + rgballsum += get_colors (&pix[yw + (start) * 4]) - 2 * get_colors (&pix[yw + (middle) * 4]) + get_colors (&pix[yw + (end) * 4]); \ + rgbsum += rgballsum; \ + x++; \ + + while (x < r1) { + update (0, x, x + r1); + } + while (x < we) { + update (x - r1, x, x + r1); + } + while (x < w) { + update (x - r1, x, w - 1); + } + #undef update + + yw += stride; + } + + const int he = h - r1; + for (x = 0; x < w; x++) { + uint64_t rgballsum = -radius * rgb[x]; + uint64_t rgbsum = rgb[x] * ((r1 * (r1 + 1)) >> 1); + for (i = 1; i <= radius; i++) { + rgbsum += rgb[i * w + x] * (r1 - i); + rgballsum += rgb[i * w + x]; + } + + y = 0; + int yi = x * 4; + + #define update(start, middle, end) \ + int64_t res = rgbsum >> 6; \ + pix[yi] = res; \ + pix[yi + 1] = res >> 16; \ + pix[yi + 2] = res >> 32; \ + rgballsum += rgb[x + (start) * w] - 2 * rgb[x + (middle) * w] + rgb[x + (end) * w]; \ + rgbsum += rgballsum; \ + y++; \ + yi += stride; + + while (y < r1) { + update (0, y, y + r1); + } + while (y < he) { + update (y - r1, y, y + r1); + } + while (y < h) { + update (y - r1, y, h - 1); + } + #undef update + } +} + +static void fastBlur(int imageWidth, int imageHeight, int imageStride, void *pixels, int radius) { + uint8_t *pix = (uint8_t *)pixels; + const int w = imageWidth; + const int h = imageHeight; + const int stride = imageStride; + const int r1 = radius + 1; + const int div = radius * 2 + 1; + + if (radius > 15 || div >= w || div >= h || w * h > 90 * 90 || imageStride > imageWidth * 4) { + return; + } + + uint64_t *rgb = malloc(imageWidth * imageHeight * sizeof(uint64_t)); + if (rgb == NULL) { + return; + } int x, y, i; @@ -111,7 +202,7 @@ METHODDEF(void) my_error_exit(j_common_ptr cinfo) { longjmp(myerr->setjmp_buffer, 1); } -JNIEXPORT void Java_org_telegram_messenger_Utilities_blurBitmap(JNIEnv *env, jclass class, jobject bitmap) { +JNIEXPORT void Java_org_telegram_messenger_Utilities_blurBitmap(JNIEnv *env, jclass class, jobject bitmap, int radius) { if (!bitmap) { return; } @@ -130,7 +221,11 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_blurBitmap(JNIEnv *env, jcl if (AndroidBitmap_lockPixels(env, bitmap, &pixels) < 0) { return; } - fastBlur(info.width, info.height, info.stride, pixels); + if (radius <= 3) { + fastBlur(info.width, info.height, info.stride, pixels, radius); + } else { + fastBlurMore(info.width, info.height, info.stride, pixels, radius); + } AndroidBitmap_unlockPixels(env, bitmap); } diff --git a/TMessagesProj/libs/armeabi-v7a/libtmessages.so b/TMessagesProj/libs/armeabi-v7a/libtmessages.so index dbd6f46f7ba7a4a0e8f3398b9c3497fd2956fb9e..7eb3f14a87a1d1b1a7639a8b98d12c26b8cdd5a7 100755 GIT binary patch delta 65535 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

    czn7{Txw-{*eFQ(L`zTb1O+lZtXd{s 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 X>$M1HL*h5LF|3 zKib4^@7Tn<&y|V0X!{AD)7#t*IC8yI{IaTC?B7u?N?he4lhCVA$~`-8a4q~(if>j` zh^MbR#1DVx5MNzz2*)Y?@JadO@Vk6s>wLkohh;1wiyHdZ=(p24kt2I)JrD>{cfP|X zOWVZm>*;HN8;fi|k2$2Fme4Uik0U%Eeu&e6C8%Yx@01*~Z0We7Q>=T7kHW-RoxM))2e&W>|Rmb zLxt{2-I1gkp*lV(cW9qCzt;Hzpznz!8>+w_D)o>W8aJz$suE_ER#lSfH)<0V-Z4Xd z+r|mjr|CX0!TMRkGlYsv(X+NiKQke#tc%7v>oP%3a@-}g?J5<|=(W~$!uIn7;m9AY zQg1uYdb?Q#Rpq7%t3i!~{0m5_Zl76YRn=isFHKSeDL5LZuMjGAzv_;fRj;asslKiT z#R;6ST5E!k-~WbMpQ7TUsnj1-A56(zn?BJ|Cgxa0QESZTg|;rTX9n-sc)GDSwG2RJCDN^Qy8{dmUE zH>++{HBmh~#as0g^5<_%b$6OoMpeC3x7DBl!u=_^vuxo%+_N|I-52HIvMf1n6${HUwR%ihp;eDCtF-Ejs(-kPaF14nqxYEY5rGeS(M%P_?3gXc#2j;iVoIL)bB0I%|*Gj zCfhYB}-chQ)@gWSZQdQyBQU3ka7qK!ij2Jy%EMg5U`lYhG;e{HcG^y=r+ za(7vCJHIe#*Keg|U74C_M~~>18M2yqL&x-eGxFh5zP5r>`e7CM=8eCuf6a)A*YzK% zc#Eg5tNK+VrmyP%Qt>uZ`5SumW#ST_@VtIdMJ9dU9sTHKxtDMA?-!b>Li1;usyloU Mn5UK2c#IYQ1;%f2g#Z8m delta 58043 zcmZ794OkUr`akez=FH1E!;6H7L_|cap%Iai5s{J6iHs#A*2u_MB^QZ^HBvGXGBPAG zR>&bEC6MGBRtGJA5 z><%}^f?n}teivucSQ6@VOt(_K4E4xHPd1b4eAKC!u2TIH>U@{wZAIPknkNgQ>5Zsk zv3v{FN8H$*tj1-#PGN>BEWkWE<_1lmE=O%1RkOYZJ5YxOPNVu3)HPKV(Qbjk<<*|d zo0^|ObNm~gY%kU2=Etfk*0_Z)&BUisU0m8}Bs;P8kc+h&`x$ixreE4TKM%&bT&9Pj zF2eL+`g|7g;ox5SfDG3U z)cn?G^H2w%HV2wHeIx3GZJw-z>RQy@+bXtrB^E}Y`O@~^jnze>zSQ*}M$NF8OQ-K? z)D5UZX)&8nXTRymqN#ot^>LT!ZK&fg{nGs3qYgzKK=YsXF<1R&Mb>3Y#JZY_BbSAX zaW#7`Toz~%eQv7opSD#zUAw1wTA(0CNqbKChAU!>`yTDea9Qk4tB4NXb|ML8ao6g6{M zKoshHd_Ml-N%Cg%P^W$~g$2!Indq8>vXK=n4% zu08P`)RE|!=6~jDIO-VG4YV1?2OwMYMN?Tb1J(_?9R$nWZiM+?z|Fhd^AFb^}hj?@LHotR!t2QC%$2wz`}%?o(z}0i>E3K%^m0pQB==G9q-}Ea;c6( zJ$CJH^WTqJ!t^+r{xIr>U{97!XEqCULZ~N8q3QXkU6=R5a&`@C!UD2shE15E8XJ@$ zO>WTZs9AW0|AT=`JA5Y}am+5-jpnj|-@4o|>H?SA`WGz5r4B>A)1|%}b>x-5eSRtG z%z%n54+eUtd;hjOrD*Q(t~l~wxR@DOapA$h!qeD@1l$tLgLnZ`D_s`qoyl0SOC5^3 z&ZWKwwc%3#8FjqNMm&u=!hdon&E=P%jzV2W$EGe5bi%rJ`j(!o25I^&Ap zdeKj)i&5iPUff`D1-hZjbbr+Ks9S0Jji@uRftPy2U8vKrfgv<~$qI}c*M_GsLy^l2 z>wj0jin`8a`uo4Dzd+sYGX2!=>Yq_NU8cJgX8qrWD^ZVK{o6>7Kplhr7e-rrH|k8( zm-_QxP}iWg()6{c>s{(sQM>lvt*8V3fFnr#x$y1ZHS9$lgaKhb@tNnW<#%-(>QGEC zr|BKPtGiK0V0sBn|NeLN5C69=WP@mE!Uyn>aB+p>sJl^LI%l4b{ogteb)U=h>rs1Q zL|&Rd26c!_eJ|=LmwGYk-$rnu%Kn0e8qAPK8}P*M>eZ<0G5u1fEc{*lBI*WA&!Eqj z|E{k3U0s9P2UmoPov;vx_L{1#y{OY&>S5G*F7-I-5|`QoTONf6 z2lGEK_S1xqORbp=L1>8l#~%MB0~LjM7@v;$@=5by-K>kqVzPuRBg;wiVcwj-imWEh ze{GrVb!0ucmuw;nTPQLAk!pURjcg}7$m3)W*-M@#`$#8gkR#+MIYzQ~FRrhUNs|e) zlJ2Az=|lRF0b~#vLWYuIWCR&WMv*aO>_u@silc^jGJ#AYQ^;Jhm@Fa7$SSg$tRd^j zda{AsYl`)=CTciM_K`k2Cr^nV8AryGd1O9WKo*h3WC>YLR+81Q&^+fg)KEv(lRL=< zaxd9Lwver48`(~FkX>Xqd7SLoIi>Jor|YGLKGI1V!6N9L17WHDJn zmXYOTCD~4Pklo~QvapAeUh*{AM>^oUA0P z$ZE2NtRw5mon!;Kmu%WigGKowfQ^_?Kc=eWa5#$dQX;{Ebq>7|GtJK0sPYchZaWA^pezGKdTzL&-2Qf{ZjZ$A1(x#E`LM z92rk0kV#|;nM$US>0}0(NoJF|WFEXY{`0A!fGi@5$r7@REGH|;DzciaA?wI`awpk9 z?tP!ee-kydkga4J*-mzlU1T?Toa`Zc$sG*DOA^XS?lI@+`PI2a_A_Lxz!2rsnvMqlS1gflMM($W$_o zOeZtRTr!W$Ckx0TvY0G^7sr1YHI$Q;WEELW){u2%J=s9+C7Z|=vXyKj+sTd(X#96k zLpOPx>>+!}(_|m%Bn@(e93{s{wr}zjNTii?-$&!$iyC}LKQe#}B16bfGK`EMBgrT- zhKwcS$apfLkdh=ag-j*W$aFG;%p|kPTr!W$Ckx0TvY0F(3(F`eCo9P+vYM&SX? zC)q&mC7Z|=vXyKj+b1n#9n{c8c9X}+98uR?56|L5`54 zOzX)oGBxA@}GLDQV6UZbog-j*W z$aFG;%p|kPTvK!W=TSpGSwI$%#bgOtMwXM6WEELW){u2%J-L%?fEUOAUTSC}TgXGqq^Z&_& zSxI-&i}WG=$N(~k3?W0wFfxLSB%{a}GWMbve{s|hPbQE_WD1!|rjhAn2AN4_leuIb znNJpwMW*KXFQ$ePvWzSzE6FOdnyew~$a-=o*+A|ko5&Wj614L)#qm!K ziEJT{lRacFId)NV{Cz&Tg%asQ29Tj-6d6k~p zUt;N@h7pn-ncN^hGK7pFX~n=B^F$$D~c#T#d*YX((gM=EBVTYqEf7n3VVBXh|- zGM_9Uiz?nbca^Q2s>+H_&)p#GtQb5uy|A6yI>;`vn>%qV z;z?v$;WHMNiW~Q|=VX>^`ijhopfBFnD>lUoxh1A}ovX|gUr#7E#TN)FO|QVaSEhKS zvfA`IyiQ|!8{WM#&B4oTrmOM(sA)ca-*5U1zSsc^eX|ADWH$U=U@fL~0&6vG6j+<- z0fDufo)TDx>3;;)WqKNi(DVm^9XI_^U_GY&IHIOF#HUS%1=eT!lfay&=LBY$T0}N- z0QX*lH@=%vN$R+o4$-Vx6 zURZX@`u_`@0+)RBCzn&;lJ~jfy)OB2m%Pg*Z+FRCUGgR~FQjwd;4-1!C9iSGt6cJO zm%PL!FLKHAUGiL)JkupFOm`_#UGgNCJl-Xbb;+Y#@(7na)Flsc$^Be%ugSddV$Zj_ zOkghgsNr%7T=G7byw@c^?vi)8=b&mpsWOk9WyqUGgZGJi;Xpb;*NVazB^c3%Pvpf}{U*l@K`% z-`DG&n3#~*wjUUKrT6Iggrj{Mj}8*N6zNN2@i0%EAw&pBTZj0%YlTuX9UbIeGldOS zTZJdvcb^BFbsw+2QRozaWh9 z%l*RGIKWT;QK+@xGcEmk=|Uk0*^YjF*FwP$S#>`@vQWqnkoNWIv+oz?B0JK@v+ox~ zvoXF;UzsA5AQSuec#4oF_#QEmhnMBdv|E0$+G6c(qm|`HjQC+acagBy`-tHjnrVN| zeyRP;kUsYTVVSUkZ+SpS6s03Z=^%GLDEJCKM~rc2_h@C3JaCsR*hB3{jPp+2_aUJM zGu1hH^Fu<`u$bGtC^}5jldNfb@hzPk2IzGp9TB$|r;p@6U}~$G4*; z=>j%CH}i8N%fZ8Qg)nnzNBj7aCxs(|5;4t#d1^fTDd9drwtKQ9yS{Ff@QQF3_g*cO zDN?)9Fre2yD};Hr8&w1Pk1XiR(_a{V&AjJXAylx0O}KNlPp zPnHOs0-8bx^@dU*0T~PT?IY8LI}~D zDg+N9lpn4TI?cU|{)kuU!uP6hmA-15Fdr?U`}LM>LL0KSCSF`4ygEhp@?=9_^S}mS zh9vrb$?bcEGm29BnLE=2KKnz#u81KA`I?V~V-`_r<;kB438M6g(J;hoKNH*(@tlXg z`%7&7kcWPAr?6QZ^x$803Ny`lM29}sCG0}Bqo42kT6oM&aeA;crw704d%+ z!aoK1pB_y6CwKG;ABw{F`VmzO-Jz_-*~XZ8h&_Ks1h)#tDi6ZNyre9R`=;g&fy?_Y-IQ8p(8>kGO3SW z7%>NPtC2O#!_Ny3sqz;dtmI?9@mC?nCLJ{VhxJZH{6*N$u_@0;!aiE5y|S!r%DG zo5hWi)MCUt_1qY7JF<}h?th!O%_gt&U@M>F2khc0N&3*(<>YnuiqER@N)NU?j?cJX z+$x|spigg45i_M`Ckz&={v!O;zpU9vbn@kC;vx%{P~*^B9}z>4l{xgjN5rMb z7CZFBba6Sd5C?Bc7dHz?Q~UMgrQ#g<5f4^;n_jw9T!qH*J}xa2|0oKJdGe#;VM*F= ztQ_P4S>iqssjrhC%NDN@gd~39adDLuyVL!Vp0`RImzs>jL;9{xaUCCBE$)y|hdcT9 z0`W&txKrO)C@w}zse?NU#YRg&lhM$}eo>bXrGNP&JD7Tl2lGXEBcxk+^Yh|kf^ajR z@q+l3EZoA+mx?h~i5qA7^tlz{CS+Usct?e}T#)wR81lKVid+z`=R=!CH`U`R57r#$ z!5R@e0=cqPoF`$nw0<66E9O|G4~&pOy?KXt%q{7^ZtRe^2U~y6jlce`_*aY92gayl zrd_e$H^L%5z~xI1*e%B56I~8HeYY5l?0`dGzgrANR`1}AyG2~CJ}~?pyt6@^Dr%k{ ztY_Gb)eX7vfkrXfBC8%O$I55z6V)k##AkmhzAGr_-I@5aJO9sN@o$2X^_?5Df5+Ff zi~o^44R;oT7$0_Lhlkzu$G#N(Mfl>EVvaxB{18@zxWIbNnmF%FU&F7ZW5`{f(kZ?! z?J;Hza2)-EqUdzzPkb$|5yXCXK5$h0*+XhHJRST@uQ(zg_3q~I* z$K077v09ujy>INicm~(<&^~dth&p+YFL8*+&Ghtu9z7@~AZr=mrGw%jvoY1dlML}n zQRvWf&Wdx<64tNB-ef7!BhHDHD69K;`#JF*QE1n_&x^C91|xk~k3BCQurwGmCD9^A z7wJcWEqR#K+c(*7+pe*kkfisF2wV_DEq7`{nLZS0@!vPcGAIZynR%kL)4Y3O4<*rnZi%pnjd6VYG7J6)LZZI!ua-5^JI3;U9=X!eD@ygo$guABl%*8e zu3>%qQzd%5nf%;4p7nWht;In`gPPoSEFd#xleFRJ@bt7Fb?z6Yk*WU$o4! zV0FbG@{pG-hPh^~S@+v$84)X|>z=Pz9=q%ccUCsljS2Djak+Q1gBz#v(pN0o+~qKL zRvyN~t1T8;2;{Thv?N=lw~UrSUh1UfCqG1+61H<9s237EY;%DoAq^FmIY|> zbMUS%i=l|45&Y1%mPL|S63+d5Ea7g_o5qPDp75h3!6JrT&9^u#u_D^Mo&2QJ67MP1 z7*6NgvwpEykvaN!xJ8<(3Loqp1CwM>kT8XPfwmBgZGjksanc#~wmS$fS7 zoqQ}?dQKD`(APd8rJ!ZAgCBcBx=Iof^z%9``VeMt(HCEW;f z=sU`#U}WYYE0;c!WiEgqU1a};5>5l0I7&|YbtMPbistg(R4Zj!FR&+m9*v(zW!BN#@} zt7jmJ@UgU1k}8byVSegU={i9c+}O#dxc6t$Sy8Nij4MYZUjfq%rylf$R4wkv z;s?Hvd}K8FVn4g2I|XrA<5wJ&o)yt%j@)kPHe5h8{?C6%8x&D`P+#67g^R~i_02s} zg!HPhzga)hBmGDCm%i(J=?ZY30->9CmmC%&#%I*&iCaX(*k zN(z^i`b3QtC-PlCN=HR8uh0zVNY%Jg(Eqv*yL=fU|t&OchoP3j)TI3-? z%({uMk>#_h^or4r=X?)2Kx_)<8zD9A@{z+Z5zp5redJkDui*K*Vg6qSRLd17*fkOM zTX08Bo8Nj?7GE*S1|++OU9`K|S9sm$h-6*^_!~n5Zo(_Z+5sLrOayakPnNM#!Vy_+;KeJ>yRK9wATPb*Frd@T7k9PWf7J;ZAvukjca2%5IGyGwpp7E>1ULknboL0S8tjU_zDPu(lGs?y8GoP&J({j$HRjh?cxJVfcg`H{tP zr>Ly^3CFaTZ+%!^E{i4K>qv@u=`y)gviSAe`1DNquYy!&#JBLW6>_MVHh##PvSf_w zB<=rSLD$}_YmduU3AgLB9+$7XEm>pM5B%O2?|mljp~tK4wtmD8Zg**Wo!U0JwEdIX z)+Xzl9+w}IF{w0NKl`}+yqvDFqmSroa^yRONAv?Z@+;F8YHaBv8cRovV=Dro_K3dp z33<=eOYk`~twq$BIU*mCjEF_dUZT&&&O|-uCZKP%;@-JJb4){WTGZ`1$sr2O>M z;2UjhEW*a-qHzeChxFW&@;8FC!8nC~EI%bLHPi5ZJkZGX*KF>yvGs`YGd9+aNJL18 zksoZV7?JgZP5))JJb{nY^y}mK@+|KSMoGUG%&rk)6#EqW24h{n9{sc&fjPYT^qi;V z0;$C48rFxNmSd1L4C~=*j13df% z`CE%{v#xBAbHiT5Bbx2rtFxYolYe3V{btllc+priXtCD^2y>pF&$^;M>I;bahy_J` zw0^E$yFt$Jc@Z~w_luvH>pwZaHmHY`%6|}U;tNXU`J!0zwZ5@To*_nc>HEs$gE!uw z;qjJTe7v3bx$R*7#af`ciekg7rnC|3h~0=v1E5EPo=&<2L5KO`m&E zE((0nn7N-Fe9=hUZ~fqdpDTx0sNX?3$h>5|Xe8{{yAR5%q!*3p`}M?DIS`rWem%EU zo+-HNTUzBpw+S40H;uh$v^41XkqI`jo?a*F4ALq5n3 zTJ7T1>kaEceP^4z7gM_i^o&pC`N(z+=sP}@W2NVfQjFJ6<Z_ijemAjjurx)HvCr8#!g?bv2x^V5!;b(LZn}?@vFM!^Md!NjjhC0 zvIZ6*l1FX)+GBF3Aav{Jzm-#@b;g1rJ@L5gM20P#_nq90Z26$>dqUn8_+J}ahsYkW zu@r>!9JU3q3sHW~rhjun&Jw=n^Zto@t~jrVulZgcl48~w(f!wC?)mSUCp_&}eD_x7 zZF^>-)2uUk`d$o>23}MPGFh18>rngn&&3n@=`8f=E(upLbB@4%UUy2KCJLYN=F{?W zL0q+(2cMB2QiV=^?I3QtoxE{S_7bG$49@}m@DOg4&*9%yJY`tU78H9n#!R+;*pQ3S ze59Wz{v_MYc|-d3s5a%+!1YG+E{*;jVW2&`F2*T&@;o<)W@Fw?GLD~pWe0X}bBb`ykFeZhph4D6ba?-yEM6_xvi zgC8tXHd&-1Bh;xoEy_YX&(D*T0a4hm&r+2#_abAyL$&wg=NS1-{E(_RM9e#@UvJQq z8mZ6-7}itVlvd2Ps?WTq6dL=6c#yl&BWeYkt!yPCYcp4-C`UylH~~*$E&SwV$|6~b zu-n+#yY%SkO0%;5E*o2V7r!uFIU&zJb*GJ0BJ2naabiB6*ATN2sdwO9#^QklF(2WM zSbn>%1S+R|*BaVDk^Su-_ceC>xCW1u%Ml@O>f?b*rG9N}1zPhDASb zWoa*1+4wr{8>H+}Ja8q6Lxduf?flpb3Lfimmqheo{-rPI-nS|<#MY~M^sS1&pzT^=Wle|!%lVQRn#0OCyd(Orh5!Hx%Lc@}UAeupo|=Vi|}`L^$dYgn}r@#DyX?Q$HN1+$}$Yk-S0ozDwEm2ORZYL-%0qV9e^l&s(fVb2(c9J-c*#m!x)Z%t8h z&@#`#z5b-&N3_ovV-6m-Nbxk&JcqvM0p%GXgCBiBX%v*E1S`u+;H3{LKf1{n$;prL zRgWs(n$kQMTQZk#d_s9iv?b!om4=R!rU$Q7xUfJ!u~Ip#XmjxAmFDQ%pHxmM?z63I z-;I1@o)Rc}KW*gn-{G9@w(rNTeo1)R$n56_RwSyDO+VF^MI9kdGhdW%6;Or09y&-S9Q}IJTS_;wV-CH1yHeu0 z$|!f3^Q)1o%paA{cw1R^qdzX67Aq@5#EDk6tYds)7W6@M3RZRmk%#DER#uIOWP0=4 z$`cC4QvHOg-%zjQn0X5Fzt=0v&3t5B)u+6p=vZ-fzrN!gWwBO1uCgVFfT_CY4rP|5 z^;cEDb%(N6xQsXNP^JrVFmA@d`muKv3|ic)5lb0gv{Om6ToJMxYrUYd`dwCbXjEmT zh&70mQI#LutvoAE_eHh#XO(#&yb(c&qyJU)`x})NSB(5uW&Y=}YDAWyvXiJ=5r;9u zw~fk8mQ(*#`IJ4%AH=C?Xih|Y*fKsb9dY!ms^9&A@}Qb`PGu|4sruU=C@;H(qX9r{8)`n|GJDM7yc3w^;! zY>^rHPlzn#{!4d4RvV27G=Qyv2RVE(Rcbvxj=iBhvHa++UWr4B^c~zUf@&~0^ z3~tlI&nS&z(kJ?Z(TYFUcTmr9D0cDmL4BV?DOCy%;!o@y z}G2_w|O8@$ve zL9Bj5&+=BcYiFueHiT%Y=KfPvJnGiO;}PU_m8BwPAe>wD;A!eAB^de9Eqv=V)gdUA z71*uU_{Qn#VnHmf;toG`$WmCNV{B|hzpTO^phO%(U4&SKn2#vgtg^tDu}!b4Y!nfU zHYbcn`(`+T7(=Wo!)ZYTqum>xMcXOF8pMGODq9M-AQBME5mAW9N>zX0N_B(SSgD`7 zQhi>21J}`7Ju6VfALp**rGaX*Al7f<_8|3`D0aNU1Fuokk>y^wKt<1QAufIWEtZ2?> zvF!+ZE_d9d9o2o2MU;qfQYW#RfK_2xTNT`sk(S+tmsiCdTDp2<7PW?^a*8<>79UuCnUK^)q*?k9ibZ+49HH%O1g)d0bx-uf9DE zO>+^^XqFIrvsG4?t^41ja-mp1dXG9oWJ~ykd(`Q&{8yaIEbe=sdd?<4g$JakxaWiF z0X!f*q<1b>@0OpmvWO>j|A*8R=`mw@A7A;9Y7vBVeN~$Jwy;DGd>Gq#Dpk*USlwdH z!Y_Waj01zZ*Ag`x)lyV-gSvf*I$u1L%1f81!GaQakIIfM;*F1};g<0ADAvWJOD;lp zL^%GWvhBa%3IS&=va(8eG(}|{hAo52-L@>8iidD7U!gD0 zP@|nScc?z>Ouv%8Fnl z41t~4ueFF8#CAmRJ-j(bog+@eqv70z7zK|&#IA?&^z$$m|Eh)w(hB2PKcBr)y-&O{ z&B~e)1%E^b!`{WhYV7#+(LCi#Lsc(u2bvKV*c`VojM^1xABw3 zYMy{5v+u6Q=HYEB2S2=C-6D#oX7i;R)NPUno@X~j;_2rOD?1;{JvXX5MCmU^>mY9_ zSAP(MEA-k;>Nz>u$~vO;EfwlvOib+K8I|fEMcZ{aV7FLV0Dhmo8J7=b)m6BdUBypU zsh*09Ft1j9M7qV_%1%zl@ImZE z978CGa$j^iMCVl8E)f1cDvLq%A`gaAbg<^&&3d!C8c38ZNk+e)xSgOSIeg>_+vFFvW3J zVY%<%3ip%30?#VkvRC~`_R28ahdipLTzGC&yE? z4fFcXR9TtfhM_c~u;qva=M6n^h#tiu@o zi*>DpG}fs%J!ZW}PQ{~C3RkkNV=`L(`*mfdwH{eppWe9A`jU+6X4)V5{3orWqLgZk z5Ak`cthY|VuhQ4NVAT}q0VCDPOJ1^mCkl~#=|*dSgr=T8zHXECUh_4U&I&93HT{6G zV}Lsj7uCSKRxaVf8Ly#7k8#Sg|&zfn;pnmo>YZB%k>(lL9tWVlPF+@K> z2biHB+G4H3EICfT*Y}wbjS`RKftSeZv|p%wA-84SYZ9Q@-IBWy6>Ko*U-) z3HH>$MTRo4H1oi{$(hf@;RpABot9<3787M(gx?G6p4+U^Si~y4q_@qw6j?o9h1q7s zFS8aI4TJn-jdiNv5v(%n)wt9LsjT)Yef&-9{enMFuC*?)2A2FH;~IilR@LgMIq*3GJvVl)r)><_F9#hIQe z8{eg{_RAGkGl4hOvAj(`%dGP<1%E?bVNC-vYqBa#apPyWHQH0U-_VBjki*u#E4H|y zhimAh|HDVHNlAzq2=`xPe(h)0AKZNdzn59vsLWoB#n&waJm$TEi%l61?zZ}RD)TyJ z7FfXNow7!1(n90(Fkj`g;?0GH1{>C6hOBYHIVWZ2k45Bsi%Z0DnWcOyvzYH>*3yGF z?vKeVg6p+I*0Pv|hGWQL*X#?Oer^HwY4(N2si72y?D=K?T;cYSJ@1~nbKuToheZ*M zJBxzt*I|0jkeB^(h}S2whVkAQRvI(N+kUcIJ)|UK$sq3>-&AArd~3 z8GaDY+&_|;y#+_D7R!78i_>iDv_*}WnoudTIBdJ}vdjYh zrm!H)8IEYfzLX&R5V1RCmWJ4hZzlwo;F}594>Lv)D-jA}WIfstz9sy`RW?tH))S+! zHbhL3em2;)MhSaMW?^sfmDkt;Ei;mCQP|3LGCNg=rTiUx5{0Y$b26($e)nm{YLPFg z<@;vXIxW7+TA6Kn7X7aV=XIORLJ^Lw`j%O?rJfyIaY!)p0a*4N*RHcQYV*rb#3A}{ zTo%2K4{X8LH4yfEnFYNjvsIh1rdMSaf+$Dy;21=pEg89nIQ%LfzsYv$GSBXf_&&#r z*h$2Z^?c}V+jLdNMfv3OT)WSPe_kvp;HMVa4#`^JBRDO%MkeO-T@TpK+r(Xu^X-4O z?NG&icAmV#cF5iH>@708@Q} zu?n#q@dR$-Auu@>0}IogN!V;eR3f?vJc)0X)F8r8AAl0v1#1yo5W(|s4Dl_LwTL1_ z9;PS%QJ%wMP{iVEDnW=+?*uj`*p$} z9tl!d@EtgvUFa7u0uhP`K+KNCmc+h%Hu` z&4O#M#L&DRX9tmnXh$@L$!rG({bo#W!sYYyb(qgh-}t6&TwH!V-&kwA)$KN1ZR-#n zO}Ns1juVB*Lo7vPWB$3g@hMZ!9UL(_vZCdh2TQHj-$OZf4e#AY0m*z7Th`6EC1tHefs zLH)JFwxBJgi+dllIm9U=Xx#jj#5@t>7bNcXoy{hQ1)cb9o2^3px2(T=!nR8LHxBOq zB$oI;Nx$x&w#T)qBNFQvmDtiFy!M~A?ZS+%&m~rXu%j^(;fuWfXNj#toN1TX5kx~f z&-osm`37GU$IeUaC;~4uvF&i*VTmn<&QB#a>%aIg89Rb)I%Rvy_E7bJ#CkDT`Z=uX zti;a$gt-wJ$k%<0_(Wpi!x9@Clvq9@^dpHC@0VCL^0XF-mBaOjRHwv_V_EJ8B(}U6 zwF7H#+V%@>ariD;9>@C8^3|a21@)1%eu`;!Gj}ck;9Uvt28A;EpnakC*-nyZSz#@r%t@P(siU{~ez{ zW?N&4?(4y!MJ&aq7aWsV$=ed^`zLl9CoST8i6tS7?Giinj>KvamB@FXFU{M|&rjIS zh`|PC?nUI_GMZV3@9QByg*D8_Ord|rkvPG}MQw}VzX=VwwO9*WjwpXqVnv9&H+iF^ z{U~~DN4G|8e2atnE#Izc-WJifn>TA(mL)jt8;NzIzn(#O>DW_5De}!9O8Ea!;S*nT zyQiiJ;>jvKd5U)4cTttZy3kKsUX|D?xE|)dsxR@v*K@Zn| zDY2mnY!^D&Qbg9p;Aeca>Eg_{Wwsc1-grb5;_yD4BJ|qKOk7NmC%l5whdTXpK4ZFu zmtSu;D*JWc%e7==nf-e9<=W?0et@erLM+D-$MWXx#W!m=;4`mdq`l6Q{k7@xU2ozl zxChtLIt=YL>@nhGIj*UQc;smfxOE`by^m}5Zd{9@V;8Qwh_#y~yf}x^y_@g4N;_z| z2e)SpaT>Sh9M zybI4j9{&;Fca0WnlWxPi|N4b6t-=2`e8q>&v>v?LuKZ2^QGV@lzpL@RncIx$0p51K zHsY>?C!xD1=?9{<5-G;$aq0_h)n*}UbMpLKwSMukwK98tY+|Al-uLUo#G$o(1E}R$0 zZqm(0@Q~h8qWNn#8$LtAYd0HSLwawC7K$ks26guhS{5?=W^2s`%^%rbym_%fi$hjE zsP}Hr68vvAG6(UErCb3kzu8ziScHGB+<`0+KTa#vLIZBbJ+^za>Bbu~kBxejTXuan z8j@RN_shE3d~_}?)&61;Zs2EM)^>?lXrP1Fm1{>OX|Az%n6G(N3l@>q4DlLW!^_2U z&2K}czpnY}VXtcuD7!9}iOBHdp^FpRU)N$#7El>jtwo_sp)$8x+iaO@jOp*cu1(Ve z-_SHvj>#%^vO00G@`#0;M&^&FH z#r+ch*LLj=izWF7iC?or`%V(~{fm$9(p1@oTVyFNNbCQpd+yZ&vA2l_dBk4rJ&U05 zlUy5C#R*CO>Y(;7OnR@0H@0dQ1S!(+!y65UG#_N{{d)T$Z7DK*gCzVDZ8ow4__5O` z+K?p8G5g%2cC9{W4u0-(wf%YfccWo!j^P+&GyM*_+i%{V9{8Yrj&XL72Y#;M-Tpa7 z+#t_CqBV+09Rqs!ms$q0eFJ>+m)cZC#IC&ijkZn^PfPrU6IzZ{?3MVoQ`(JF#I&va z=ug^tMJ%u4M@F?QC>^JnsG;L`^TiT{Jwh_`29S)|b=$JzVrHaZF zG_9yWutrNuELfiNyszN8{r}H#JUNbUKiB!a-e2zPe#sq*Q^AjiJddB6d?#M;K5=TY z{*3sd>v3wht}Xt8WcTLowd^g6Go9l53FFJMMY) zvg9mBCVpQPTw(jL+R+s@o|TNB^UYk8fdeBm^5A%zH8**{fW-Lnb8LC?Yx=CK+n&u! zuBGe75zmkFlYftpbHvk`pPYeE(uij~Ke ziL{P+(#w)-5xN84AC)CvZdR|udHK0N2IC4%+pF{cJd&j(HtOrGkzXB;3ufWPvq;Iw z@wV)Lrzp@;^!Q4)axKNATAJp6@Uy-+-UPY|k0-#^+lz+8eUv#ym%HlJy@*`U>oXDh|#JCco#2!7$$b(8ty zcm)6QLff9(%xibfn-fXtP+m5yz6OhD{^~gqQ^%ahypA?olI0(#>b!05pJC}wHrgVW zbhPb1*WxxH_}k~(R-A9S{#0X1q_w@xmuLA#kKZT#@MX`|m6l3`zI(|tC*Sgd?vb{) z@-5~9V*+1={kYDOj!@%QZSjA$M0BYM5o0)hD(+_ny#6h+j2jd94oK1ymfH;T5+eDd z2~+VmoU;Ajk-4L7k8QB5)uRX-Ud5=l+-NYyM@kO26*O3~jK;)B_w%0WM$3=l7VDLW zv+bouOQs&)C;sL+yu-3G&Z$?#!nTWdTJX!H#E7ZgGri05t?taWV^3NR>5Zm{{iU|S zrz~-JYTkBekEPlO*DqdZyRq5wMZE5`wx2v}snZ*c=tkRzt(MhsXv745@bbLn#dw{m z?NFzs%V0F%mkMo7U6xnl^o!qYyWb4ENRJ(k4?DR_q0gUS{TDELbtX>nI5 z&;23zK)!ADg4N2#=O(kFhM@9dm*RQkZOapJU+R>M0nfZX%cUt*7wVKoSQ9MprOxx4 zKFhQEab4S~2P_A4dg}$A&)>295`PAzZTY(vJQ3T_=Xt!}GN~Wcwf*Tm%VWm5BRXX* zE*Q*9bxJ*c`rHnCq}OxyhnA)D3h}=&UJJ{D?Sa{0w=D78_Mzq4h3<28%JZ-XVcGDP zgYn?CplwOp#~)fA*BSNN&m0FWPa;(Rm1o|Nr4*sAFkTF_tkdZ~)p7K_zmfKH(EQH*eu2WnHUq9rDKWLdb3&B40G6Wld*%s@R`;bf? zJ{w2ycV5;k8Eji}$g)EpZ$)I%;gmucw z3e#%cB4gy>i*1*FVR>7Rq4gw>S+3&WNvVhFwby{}o7{+_=#ejUZFi1Y&W}%Se@;=Z zjLyvDAJTdDMl9E=Z|al}Q!#eW8OwK@#!U8Cq0Et|~xN_iPqS6A;ls{392>a*Q9 zK6A?Ihnjk$sh!IvGrq#Z*G?rv|IzQa>CQ9sS&-(%k;oGdZBx#R_EqEGqkX@_zu)wU zCME5L)n_-Xh}wT7^V(v0hd+8~OZC=-bJgE9KDfQ-WxTtdmat^t<&_bg;l}l)8_ub} zWz)*P;YYAXEwBYvyKYc7 z^+r1$?u|A+T!kdVuT;24>=j$?aQ}Aw4LdDILsd64D$ZMWTpdX=uiL)pjF+qKjOeX5 zRT0j8A|9F+B_Jn84p_%-ajxDt$D?G&Tn^^zqT1~##eeK9Y)1mAJvEK zVa4RHx+1JgL|;3v9$Rn<`Ww1@Ecx#1+(URsTOZXijcUrMzFkX}z2WMy(@#l_+A@t7 zU9?^aTQ9d9ZT~&`SEwv5+3@kGk~Sx7)~^hY-(wH!Ojm>tKCr<)G@7kj88#StN8{PZ zIj~c0dGqszpg$kc>)OM5)2(4c;)1XVjZRE9X6u#*4&1)Yc%BmZ@R1uE@7t~hR*lz#6eL>x$PGJxyQ9j{;rQWd<2k6Nxp!1~6xZxQ&VIsH<0bV` zXXoZG@9FN-Y_)!<1}~F zS;VPWT+PYo9ZhN;idH={6wUIwu^5xW$t!!KwIS;!chnZLR9}WXrslY?byaV4L@Wp! zl9GORW%$#FdPh|=s!tEzaJ zwKrqUHLu6_SPN8bIUPb4_8^(X}+GipZv^{WhF>s1`-1z|H9 zGyage!QP7~E~25R&C8)48nt7ov6!)YdJ#t3(}tpTyEfS6QiDRl*UVoT{tWTfwClH_ zv8yac>mEb{(kw?i9-I@lBKP5Y-hk%7qw=(8QQ}Q#Sba1T4Kr)C^hVQFv@EH4Hd0n+ zO{>R{T{C|@hFMl(O1r+fH=6m3<)L@cM}xW`oRs8_nmexyCu?(W#Oh)H%!OR}vxg|F z<&s5*F!=JYbw@L^Pz!vf=9`d9O-g$nQMY3evEQ6I6!CrXG?k;n#6Lx1`}ak!*NQPU zbJ?0T?@yYz5DRd8B%!HJOj5?fZ0tK2gWhNs)`x5W2i~}iL$5VM#SB}HHdJHv?y`mr zt8i$AuzFW;fta^(QDL#6pPxOHv>k)pe0m~#!$o&~;*w1)G-KnHVXhyg`KmE9)`B}Y zgdye>4MqLl4R*`+pNu7At@yn>vgAa2L$jSm|CllE_g9ZOPDg^YtH zf$p-3MsxUK-3RlBqJdY8;lEpdX0LKQUWIMUcoJb4_sB#^bQd0e#ut{&MS{Y8n@sT0mPg_}K ztv2mEb7Oqin4b_ftwcJcwLN;wjw9MRdm6%+oR&D2kZ9hC&^*&vya{<9<*tdtQRu@7 zD~3iFt{cMs_vpp**Mx`fw_~rqB7Eq9XQ2`>Ch_ZLcW>hb-|yd9fmMe`_3Prk*2TF8 z@7Q@q!woy`-G1Yi`x_su5>>la+;!dE`{j173+q=@?Nk;GMZE{_ao@fE{#Ak4_Wu5; zf>joH#b;j?K6EeU-?WN5{qO#8d&6y8)@{9IyAsw}D|YC^!Z41#A-*|2{Fe1*#~ue) zg86Hsd0y03jh!&UMkQ?3c5xmfv2(&{o*mIF?DoZiXM~~Ad5_|Z;Nsyq7x|dyyej6| zjPnAHEwy=G)EvMX4_ZA}wJgRipSxb3N^&0NxqWlgD0-v$yLzLo!4I%h&wYT~Xm7Oe z;Z0GK;C8zB0UmOequz(~Vcq4KZe{V@sM%b!0edHRMXVQ7b86I_X%8ovaCXhTBAlG4 z4=Z^%{2o;ntJiF}rU@Ibz;TMEn9xF9(%h)2@yhT)98^~Ht8UjXJch7oP1=K-Q6&{=pLqG z3PoMSO0M;mM0BwEr+VvcyA3VfC>O=c)ZQ!NE72(hWs8GjNV=y0WhwoNiTp*0% zVRqfKSgJQ^3$+eqB%*@RhZOteVI6WM>9C@hQ)dgC@Y~r$_~PMH&G;wj(K+_HQKNZf z7%$7B^4n20lh2D99dcRn5<;KE%DBsM&)Xa|ySXR)YP~!~C#9uEjk$}k0adKGZY*xr zg%d7U&MEd_4@9-5G?ruCdIc^TX-rlZ%x{kn7DNP zoW!MDPEWLl6VUH39!S`kwP6{C+?sazSi)UP*JDrH!hI~OVfF~IY|R_fxe~Tyxsw~_ zBre;Tn0UbkL*kk-<^CV6=e!S%X5qqYW&!7(o0T$#pXQAv>)skwjqJbfLKL5wcJk27 z?q20vY}s#NW3pW|G`cj+cJVTg`D-2Cf029L-&VXes>j~3?EBsAE$k51ubtNAleg{1 z7&hOwHSo1DZXJ#%Gj@>RLEUBX;X30`wBeQb@E_x>YWVN*L($rUW%)Pf`?+6X^DXM+ zfSvA6#msY0z>qD<8%uVjy1i8k*56dM$UQW=K({HX>s(UJwSiS_=7lDY7iDqMMjSt< zI5!wCnv1JQ^W{UMPMircuz~-dSC6SWRi4xTFPD#_|F_G>msTa9_f3O$ZX1e&%=f(s1>*{aV{9E1u;F`bvndOsb z;D{3kuO9o!yi#?`K4t&cMk{u60qU<@Xq`&>_LeRBsibd)a6e#}N;-mJ!|^Xd*yA_o zFT^!o(3ESPG9kY2U{d(+hJ_p73}1QAy!vYvm^OW+%-M`nuY2(Z$NF^KZg@NAZA)5= zy9Tpz&c>)cvT*gWQT?i$a89vd7tC|3^EMmKKBe*LDLsz#VuANKE;NO$I@~xss-H6A zrr`j#%e(UJVWSCm1h_MZOT--l?+h;TO=+W+&Fwob;oo-#*N!E`eR^Qt7US8DMs%w) ze)F6inAo{EN2IM9OTM>u{#hN;N6r>^6~#A5}- zV+AB6o^PIA>o>c&Ka}Njf6(Q`yZa6}x5lqFZ80uc-gnEk8@CtR=WQu%yn5`9j*C|N zzBVPqdvut2tqH0BJ0IKJy8N-^N}~%0CN6hW+d5Rgjy;qWp_S_xMuX?Em9p zW75BGLOd=^OiAZxd;j(o`7T?2?}5dQj_o(hH}6=mlZ$QPw#fWjwl738dJ-yj+-mh%1za2l7u$elb(-@1CsuR@ZRBq<-2n;ex{Uu#($Ir9=k52DxX?x^+>l~f_kykyNms+pYSG?*u zywv)j{`$YS-Sz{kRj(g<)$`y5)*JQzeAV;u1=c5~7_%GiJAulz4v{a?E3KeZYX|LF+X{!2Ihmu~nkU2}BmKRPfT{?7)rkNl_p&koq? zLiOX{%;@@mI_Y}pr<0%K@luiXmN+%|#W!kjuTHqfz+h1L$rhvV9tN8Xq65SeM5UD) z{+zGAQCl)RA{2%8>xB7Ruvstq!DiDlqWJhXYQgatwQdT2l-I4%D+;EiE+SjfMa_wC z)O~u7D$-}*csgF>lgLn^u}L(~oG?g$!witxuDQFn{i#dN|Eb@1C6 zH8<&q8UowRh(`lQ$o)DIvVy^Ys7pDb_8>m}RBB}HWS}`-WTb*EsiN3^L~Tccy33BJ z9pFGN{QDC`>5rt}kODU19P+;0#K#o#`pF#if{Hi`-` z5BamMgGNI$K{hm9)4N57#wKCB{)npXLrc8BVF7xPQ+h;AMMmYuBibDIm%;xu3cgtu zWCB@`LLG<`^)Y`VI1-&v12Nr7Vu~_vm-%x^tfjSJ^KzT;flbR(#2|=-PEk^U3YRYx z_TR>a6lBY*?;r!B+I2*&M+Jkm&@DFMepIHb1#96qJ$6K`19R)7KO5u_SAZ=`JR*OC z^yh+H3mqgzyl|r`Bl0)0BEKjH*~3z>CD$WtPfBe9TZ|r2yj$ubkZUF5DXE=cu*E9O zeyNRMuq8{BKP`1B7!2+g15Hx*f$U(vss;SQ-h4#GmZ`S>MJ5PXz{ZV6bJ5=zLS^cCf{c2KPyA0$VTwBL`THS4@NK*o3Bci_~|dR?P?mTg+nQUFisc zoRZ4-q^j4~>Rr zI<$CIbS{(;?I3$>I&(tXNXo&Mvpu5xEE!)4a)S|POI-y9TO1-iLuv;Y+`CA4Go@|- zxwyN|m%0P=ADdBYv!oVaaIZR7j4YFm5Eu+TC5kSTx&Ulhu85o*sk6Xf%R*88L#Zo4 zF3zk=kq$%Ob-DC+fWa1%7+fiJKNt+|63Qy6qxrHUoz(n)9NH1!Y8{Uy7zSJ7J;J<( z1(`*(P-cvP!M$-J^i#wm{X`Mtvqhj-#`{3-3$9;DT@D8KCWy{oOWh6z_nsl@u9vz7 zM9X%I?wF$!x#$4G+^|I74Gi9wL*`!&5sxa*{@1-XN|)IT$!U(|q1Sgq-R7}ppS6EXj+ z&V8Ke10qVc#ET-g%vS)i0qN_dc7VaX$-=ooYCFh9C}O&b8dIbCHZib31h&b9K9DCJ zN8^NAcVtHG^htj^SPR|0N9rKRhE(h&cZmiPJ6`^N8J`Qb{MaMvpOLx_t9a*1Mzn)0u=1~DP;`OmsIc)hSwKC=)g1jN3RvI~jXg0x$n?V`Mx^v@=`RMk zxT|8?MZNb_QSy$AUkkRRsveR3o^)h_o!`u;ks+x^z?S9l!W5EP0l5~O2c@=yJl*ES zbPhE-Fafq$pA~__GMx_$?y(8mS5limUbxg!^Y|ACv{*gDcqBFwU_Kf$Vmzv?i4e%e zR2>hZ2R#YoDWV{eOcoW%GF=(SODkcK8sAGvof6X^&jlf{WuZs(ryf<+7AIE!{G-}d zS+sx|QiWp?iNlS=5Jofxg|e9bc_MHQX%#)^lJTNv3AooHCYDNn^#!C^{Ca-zEGp-KDWfjBDI2vLcKRhxS&)LlfKCaQCh52xq!)gU&WtRk5{1H}0sr_-M? z!(!q4ITGNoaQ<3m2$q5lkH{#O8Jr+@O2_T+FU3XWoz!{}(P$EVF6t!Vx*PErxjv9b zN8LRjj)KZcSxyDWJ19pDG>`vO1ULn55*a%Fhy>UVY;`QiBf6iU--^APw2A&rvY;N2 zi*iIG4$sZhyTn?JK~bjBFRC=|7dalps!%Jh6D2?e7 zjk`tlRvF)_ahDj6Y120PeWFw2Q=+DkdY3S5m+7-Wu7wOuKP5(De)A4C06W?U0<74! zlk|#AjX{yC(J#tCE=DiNlgLEOuXvdr4I?oXT~C47l0ziQ8`sz*%JxwEg$peBaz+&~ z?cbxygh4o1aOz%JQ8vi)bDm%73Q)VIYnBB~fNW59fVxQ(fz-8{_KOCPJ$A>md7mu5 z7-YIikPYrr_a9UDFHaO%K^7F$$cB_sqbH3d?(rPY$P8{0N5=rjf|O_FVk-i9wObq0 z*?(cWppf*70%|PYtQTTa0dnNjwJ}Fw%rOqKplFAz!1*E)1`MJOmuHEAPZ5t1GYvDnNw_})pVo_3 zvMEmVe=gHUL3Y6O1*u}lwSZT+N!+z&jW7a70a%2J*2Z+JMqHX{^b5x*(xImvWXm!! zaa86r9-~eY!;?~vfSjtlsMJLy8dgTCI7})Sz;Rg}i>L>+J)PPj#59Qpkv(I$J^z-v zNo0cE&{>*BM>P6H5y%SLL9V4?kmU`6oLbWq@?)Rr{*H$qT4Fu{2kz1GXFv>bfieji zMX3(NPze(0jCv5O)@KCK^Q<@!Q&vx+f!!LP6wY{Rzo;V-Z%d%YVNK$BLXAef7yz{d z*``UYg_$4=%GKB;>NNUABZ;ZWOJe*kQKAvo{~DWwl1#r}WNT~^d1hH&4j2sX6(WWC zt)g%ah#Q&?hm3D^sEoifpEF6js9Pi>YCtx`9n-Zj9R$lpXVea`9P9=wz<$sLhCmK| z&SIIrRAWE{NsR0`$SJ8!gT{!iRnwWUNo1Tgspg`9ERa1MIh))q%FdDT<6s8j>y|>} z2BRiR#t&RT`b6$B@=4JTvV!spCsiZTSA!6k|?Ij zz!B*3m>$uHReuo*@Ft035_4J$vd68O_KR+i4M@Kj@w;&+M53pD5*;0mY5OJ6euF9s z5MTl2bfD+mBoZ!tJoqZ5N5dorwXm&nYO<+wnu1;56CF#U-7 zNl~aVDC#us5}o8zszGEfmj!t>;`%+N8}ej6P#a;ein_Hvz^w($% zh{BapmuP%a2#_5eq{iWH&j)$@mm$D{8tFhq!Br%#0w8|Vh|fy`mZNdrA9BZK|XeCC%J!=;3z|S zAILS5f1Sz*t0=x6#G(s;Jj)gT1{yuImC|n%l_V-K-2h@J+iwJU*xm$Ub?1{PuoTof z0){@rolY72%~sKR3*&KfyADJHBjq6SrK`72s-M&t#0VJN=M=8nm=I4sNjw$zlXy5? zc{_-+VmBE$M`Tryr;A~7f1*geGdAQP^VfkDXh3~TyJPVKn)Zr`m|vBFCSi8TmS=(N zaezcYeiA2(g1bngD7=U9dQnfJ2R$Tu9@Q8W#>&{@yqA95Puwr#TS=s!069WARhm{s zH3FR52|6%D#Sh2??H~)VJw#$?L8kM@bReetK^ADPMmh}b2#In^eh0FFBy`5_Wx58C z9WZ0+_nFjZL0K^Djgb2Vb`2D64|)ILo&iQI=}x+0K=Tg@YK&1C&Sma`UQ zgF0fmqDGb{Kz6{dX*|NAR^f2`QD!IunZO6KLB{`){!CE2SgZxHhZ`T2=`umzr!#6c z$Oh-d{53J{kLjM6j%o}FNx!f?#={SDn(@D^z$9A#3}R@eNzA=ulgN5p>RgZwEYY-I zxHSeuD5gzMFx`Gpr4e7@Xv7oJ_3)#fDA{z1$k_nm`l4tf8-UYd1Oa9o-^7G?px~j# z2BdMnh%`{+@Yw=ljt5CB(u%Dhw&Vs9>03by&JE^mjMw9ag#IVRKuni5LSyH1Y?tXP zw`+6n6#+UB5!}g${i56}hrZ%T+2icpQrCbSf#I0W^U3tar^qIeqcI@7AlHCnkBl$W zh?`oCO=1FMIT`9+CI|?Z#wOv_h%b};GC?00Y&MCKr=@m-!R7@*X_6HTgPi-UW-=)9 zHR5@q#wO7h^M_(OH6ZhqfNX%;g#cSVtPu|m_Ce#YDIu{Y>i5fpgP``+Nek2Ccn4WP zc2K4tBvDS!Gt!^=tkhK?)3t&e5#=vZ=YY^S{$q{?=@302MVFeE(P5P6y6v8vP=#lqB zc{Vi-Nq;_x{lNut1l=Dqomu3E=+}$JP;Bpy(t*P&=OBooECIDuOO2h%`>FJk?vL>l zT+;#3KMa49MO1ty)7OI>;?&P4)k>tB7-7DENc~dA7lRzh)WcF|s0eUwO23j0AIJm| zkQXA6BhsHcK|k({H0~GXW7NAu4vCQ{0as{i1_9(9(zBzZ;og`73J~xPfe9Qt^k=Z0y1I2 zT+%DbG&YGwkV8B|jkBO{9*Cjr(-affFC$CKl8R z$X_5c4wB9DME&VewF$3OlsjaF0%T7|NbG2(XHa9u1lv(i-O{Mq0eZnsQ2BvuKoQ6W zl#`g6Ixv9vnjcapiw;mr5JG@GE4Wl0{7vu+SO5Y{6q8%WJLoYry#os8a)qy>|m4{`OH6)+MyyqM^?;HOO1lO zBzo++7Q~g#IEkIi@k{zsMd7dL$D#$fPh|fZ8qWzc{vXCCiP91h>93Ri0ExqJ{5K%V z%P$47hSUiLFx2iFqG~=W?gu%9eK(T0eZEOn&=0a_BP7z7mw_1C?3+p47u-TxMgFZI zI+S;t>|rU$qo9>U`l1TP?-pI;zJ;oA{+1D0qW><^DbnvJ&A3sJLzq(qjfS*q#DxmT z9+y18bW24krw~2Euc7KCd;5-lEl z1;o($U!^t+Ul)jqv;IMUyr?Bnq4PD+A189abd=Lbjkz!XCy1l0jKon<0m89McoE?J zdbgIqFG3_L%I{_d?BygXvb_#sh=)n+j9G7xxNmrq#1&8vHlPpi{azn59!NAEkV8HV zGQayB5DjU67i>0*qJC}hn1ug5I55}Q?=u1?8xlQE{V=Llqrg&-4e0=R95;R>^@v8? zI}XN1ZU}y?1?R^gdbk#3`Z8)Pz6Om!NleLvN(UB|_yojMWQIVj+Hw*{L+GIFLEa%~ z%xQ&2>~NpT3SA%@HmEU(r{K^y`6!>!k6XB55FHZKIGavr{{5ozb7<77n!dnZuX|Sb zKvs}C0{Sl$-6UFEH5yx#V6Zt!n8rYUTXvZ7`$cVp`eGp_!F?uC6QxcP!EZra^JO0g zF%o$oN5Vyoa>vOQMHL-WbTo-5iA%7x(^1v_KE5CTnV}wJO9S6A-G0%10>mP7=)cvb ztb#;=!y1EPM5AA&f%eVLnMkhK`zEuP7;d%e5 zjKE1_E{Ws*G!pxSoivM*1+u_aFxZkII-D|HNgA0d2F{V`sxv`Um~lRJl29)AR_jnL z$Oep%DkCmJ0CQx#m=Sn{LSix2YK#-cOQ5+Je<Q1lLhvH zEz3=!qXK^PJkv!ciOAjL*&_A#B<_4v5Ea*x*w8|PezVAWL~8)PEcyc-CXxOpa*imh z1JRQS5+{|xCqP_04z36HEfX~xq^_)IJe~t=BC+*0fXG+3AD z$92HkD2O%UC$ZIrNNhZ=Z)G~iahcBr@~A1C0x?3v3CFc`4JNQDQK&r(pohLh5D8P0 zsON}!3yHb39@mC4Ck2{Y=qY595OWxB74Esmu?DQ7`z&gQ2%Sq}QD>6)Htl>6BU(k` zL1pF-j%$mt0YryYQE~wjU(a{usAqx^1AJFOQSR|gK@UD6gd9Or-k^Rl4!7eVe=FHz4C6|XR3K$u@8 zaTX-8NOS%HV(7gjzIus}=y^?_te_QS{*iadZ0w+gwsXh?064|#hF?;g%?(E4GD6D z?Dv8=+0>G}RJ)%viO@q+JpQp`{ZS^Y{}X8!t|v&V@NXpXoo+pd3UfDs=y{05cfNI7 zNRy~*q~9QNc2MI&WEY8N$RswZ)+a$s*`P)oRU{U%aW@-)3kQ>r8InZZUS>!XZa;{j zuYVfEMr3SaJYKKe4`PZ2Nep>zkW3e)f0GQqco1a9ergP5@O2RH_0_xq2KR_z65oamyh-g7 zwjOG{=l3>sP&hy~XrfP+GY)D~@y--hJFWxXolrM{WR7BPVdHPUVh^dYTUHe zawEtJGC*xk<4IfrnWQdDlIco74sEeU^blkZGm>SxVKa%JXjn;HZfnFdB^$K~PeeeB zgmVrXfCS=HS#TA|26TZuzB}iF7>UMt)VLq8%XGOQ=X4lkLrCh{1u}h)M!fHHx=ddV za!QO265kDjtY^ZZ!hzFl`57Qu+`kaSRjfEu7HD(Igry)ec7dGZj+pL`#Tyqf9*=B5 z7F-Q7U8Uy77nm`Bx2AE+2eQFy)x|PlA;_N8fgDP28Z>q?$62IJ6rMv`h5cNn!}Gr- z)Hq3HPHSsn804i``ZD@)Cv~ALw-aQ~UD+V^k@kzoQ-mXjoGa9hOPOGguw6z6zVXZ@ zEn?(H^zRk9KPGpJ3XMMDC$Ry!FDDJ6aRnJCidHgR5Z`)(*y~F*jh%FrY)Bo*#pqrm z)75Ll@js3LhiVw)kmMFjtHW>L_c>QGA?|JqL7Xl_Bzn^LQxGH4b2XVN#;=k2@_x>E zd<_q>oOaNUa(XnsSM-yHCxxT>kd53-VsWlxx_~Gu2XXiqZ>9E&3XMTg1GX$Ti`)vP$0c2*Y}ho&e1rFr`-SU1 z*|GHdW5<6X0_=G{$Q~C~$%0EY;+6_z4_hCU@zWr6|Lr}DVxLyb%4|V zz~j9m7)ivpf-FA(YKK7-0k(MHIB69A6D$DVc+5zhW&TbpsKH9&y}&u&X$2I6Y)JKd z(k#piWxAflGF?|Xh;jx=y|SovbGZlm}8B2C>_&`n24#HivmnaPBatrp7tOB<^WPXSi@}#QhsgaqiC3|@r1t#-M1|8N8WMQ( zJMHva_mkk!A$C>MBWdm<3u1!YTJcU zS7%f25rY>?U7SO`TVz~Hoh*ueEd6!)B!0TJM(XUJfGF2-rPhGGq7ea}oyT+k$SM4G>MTr z$Ry#sS7jhxOg|tK)KrsZVfvHQ-bX>Sbo?<8L+Yy|@mr23r1o!MJZ@4o?h&Q+GCp$) z{XUVkl^WNA+o^X8?+&R`cae!=K=mtR8X!FFCvpDxMnhzF3R{l zcpIJ??+Y9!@zu;UX%Lm)F&^*#_)jq4!yh7$5sk_W^iv{T2kt#h6vdG#qBfC!pQuct zP86kP>GxVetf7fHjK}Nzr_RWGK#E4#F_|_NN+BZ1sXw4Nn=dcQ)9;rX?|Q^fcznI)z4&p+cnIO zuV{Xb>p#x19|5jna{5I)90GYC;9N^T-uWPLHSE?j-ip_V_W?lW4}nY{1^G2z#xIZ_ zXUA5M@d0X-Gp?~oIIm@S2H^$~(If^m2UhtnnGoOW7t4$`kOk+)bT-H#F4ov2s!0^o z^{W|qo&RfSd^u$-C9R^gOin>9$Z{G$cCCwvLVx8i_&)S7V8R~PWjWlTdi&PZcRx(!{d5B#i-`gT9tg-6IT4^3Ra~A zRt@vPCSdh$tI`MyzQEIVFh8LwM?Tb^CymZg= zFQhDqA4x~08J;nQGqSYsf)0dD%e3%M5MCVB!YRrb_%DCfuZU9;!Bb%TH2N^ozP8OB zDa&+f<3R`*KYidh%zOyL2rF)}D!E`8%mouLAFLhL51W9QKE?FCVpZy%LLP*(VFfT3 z%nkFyx?$rm@0gW;URtT^mVD|m{I|?6rEE!wqN3T)oZZ%quY5Sylef)kPRi=Tq#{>d zpJ&0#DGLm#hpnDVUQStLa3b*4dnt20u9s8HYUbg8=Qks{9p;2(z_MYvuzXkntftqh ztOe8eSe4Xaq=RL`a$xzeB3KEm9Oi;m!33-h)&TRu{IDRb9o9LF_0^3)4{Q)N4x4}} zpJ8-hHkcjegk`|8VY#pZSP`rkRtl?tRl=%awXg=54;Fy6!a87`ux?l%Y!EgAi+rY9 zm1zV_pQA@GCoB_|3oC>b!^&V4uu51ptOiyGtA}}E0az=n6V?M8fDOVzuo2hR zbxurVK%9yK`SH#cDzNjy&uy8XR`}<|(wD)1nsh5&C;7*Fu(D(RzS(jVML&q}Y{et9 z{yg-5dR8b##rEZF@AXP1!n2=fk5!o;6S=W8dC)}&FNpcOF}$b8!lm##Vh!!=wJK-C z!sYNUjD=nBpQ(*MGSxviW0@Bqt;>c;Vn%oDMK zjIk}e81bdBa##h-1*?Qr!Kz_3FgL6mYoGyqQN$^)!`_4O(;C517r`NE`WnYEtO!;C ztAhn#{jdp``5SClupC$w%n$2=jli5ouyMg$FgL6NW}ZNKu(dE3tO3>u8-Y#3Qja1Y zmJ2I8ibJv*0XM7_)&rY{r60p)0;_;E!h*0Kn0XRA8mt87f_Y&buwj@fia1y)Ou&M$ z0hsbFHYr#stPa)z8-baRWBXU}Pa&)Z7KHV|CSZ;!6b37RRlurY9WZ4YnP9~*0c(VH z!-io|nC&}^3akJoU>&e=nC%2c5VjUp4fDdlmg|ISM9jp&#*5d*QRtBqw1z{twR72a2f2N#c(7oh&?TwV3r?lbv z3Cn={9}l*U=RNnmnerR8DMcCFf)hdm3}FE_!kkZF{J@FF(RHv2)`4_+@OzQ20oo1o z!RKYT5xvAP<3!vw=1S3gG!@ zHZX&Lt*k>9s+FuPGU3uRRbSTOS^ZARV)8b!yuUHaZ~T0++qaId>4UI z8JO#-emBKzD2G}{Hv^yi3sSt9WRpYF}IGYVVsJEGgfg`g4EpO&~h!4Vj*?Wj@Mc_9GSUO@G zH7nJ7o_R0jG(&eR&d`rQ$_J=7#Jq!0xJF-O7)IdK_YsI7fZFDI3g1V3bXK{jOkY_& zDib*n&>GNAcgCz5q{@$}%^yINLZCJbpA5|P6wqBgt175!pdMnPdIT_FiwunjXys2c z-VcSTnd|vp{a_&FjD#!J;(uU96vQG!hYa9mb|A%Q=z_YR?r!OxpZwg< z9|E5updv6kIXKl?OpaUR+WqaO*$XqAYH=o;{pgiAlke95GmY=0G=~2lX=Y}0+yOmb z{VOHTQ~NLUGlV8-ODsS&KCAkuCZt+qn4WdpKZM&9iOp6nRqCuNrAmjo^Fwqs2LWyT z{B#%0svfEmsE?Sa5`mcyQ|8Bag|Lr4=UMns$~Eyl2>W8;0fharuCwn*MfvH6=4HwN$V-?(kR!^QJAq^LG`0F5c6wMnj33u?xCnYhUL#~7Jo^!C{|;B3 zVM}H9Ea%{Zizw<0Pn35KU)0S(i=Nbla=JoCMJQxcG_IjRV@OeBq zY4W@g3wAbnzG3hMY~{_K1&0vq#A*+ERxpT7Kj$USZHH3M!P$I+#Pbq|fYV;WiC}hE JK`sD({$EfZG|T`1 diff --git a/TMessagesProj/libs/armeabi/libtmessages.so b/TMessagesProj/libs/armeabi/libtmessages.so index 2dfb8c4e7bd75ba8d1af3448161b75d7bcb0f4d4..f4eb4a87f47ce4a87b2317335c2e19684dcb4990 100755 GIT binary patch delta 74238 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

    Abfs%YvP`gY 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 o@dc6&M&x3DPz$tspcAf>0$i2u(;en&^pEB&RM3 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

    Ba7B z?zYonVt?`Odo1VJE$;cTC6C=Q)_iPf#8?IYwAj)SxK(T!D_7j$1NT~<6MSzkn)s)2 zb+6?gGyC1R^r@w}P)ch~+(aN~RvQ^i|k7{>j(q!SA@+Nz13e(UVB> zE%!ZTnGVc%;od3BBJXeNO5wHkN7kIwAfKFLvl1Nk63$Pf?+);z$1|27cAUqbfx4XK+s;_VVwUpF9Q&+72M{;9=V(kxA+q)0o8F$!E z8$X@3a4|n;erM^7?SJcc7Q4*8UO!u=0y}=Tw3e?dF@F5nlFP6-ymrYFQ|EKkVMCB`I63T< zON>L8EZC_7`N6A}iS>Ie#oR~^iphx!N;)1LG(oInj{I&$w_h#rE!E>ke#7)@W!(JD zGLSKqcfF1(xEViQw=`hL;_u%rOISx^{vQ@YW}omLH!+s(2EU2%Va2?61sYS#k5-_! zKQ=ONSuP4UPr_|z=5GGcZHT*!%t|rqxAV4DmNiYp@guxUEU+QMHVwHajKnafk?6T9 zl$TdoZo-@R-91YSy^G88Tp!8h`I{@qiIVeO2>!AFy~_c|$=%4Fz(J(|zytgM7>?E9RuR!MRN?SBqIllags%4XQfkGm+ZV^N>nRoN}G zS9!xo+GQ8A{dnvOT2fSEUfYOMg4`X&p>h1<1ZAA< z1x%6DAhU?zD0ZL4n~heUZ;U{Z()j?Xj%S577YYZJD~^2G$QrG{x_+MTAEQLEDE`kF zWg0MLtkND>IaY}Q{urxFg=2eYqSCbPp10|GfrvyzonisPKm(dwd0h=jXrZ_UV4x+FA@R6G)I2vXZ(k8%5yLYG8#Qy@n)>OF(XBJ1IDOvJyn5cv6V4kmI9MJgio6d)o95Zrz;Ow3&ZzKRFehs zm**%Gfjx7S12Ar;zNH*z&3UH`paio<)Bn-tUMeh2P2D zd!UH-&QV_I@2t5`(0`Yi>mKw!3U$i=-=%(=ql{#}yzN5e>jt8xPg|c`kYC~UxVB@# z_KMmX?v<-}`#t+ugqy_U0~IQd%vBoxUngFft2Fw*PW<-3 z7||IH#ecM`r8VI{D!S0H0bbczZ^J~a`O&6jgRpOf0%PTH#x|B__pV~ zKb+$`)$B?s2L1*TxaZull|06>U>5oDn+~O+v%rp`K==2RhR?YQymk17XD-HGXrxn9 zI_|X#4G{5A3sFeNH202sohsFFZ+;OU{l3!FO+?9^>WTAW5zl#FX_V>8?P$19kgH6) zGj(*3+2+?TPApf4%l*PbgKQiM zNQl;n0G_c(iJ&(inyE>`>- zh{Owqx}mIKQSO2Pdd@etk^(ftYl+g#+nE+MLZ#2zO3q_K74bexls@ zme9EhH$G*l(x|nVPqq@5(p9LBN$JY})wzG;?^>$(`-%AftzMXpzb#doIx~mfAajp= zr9mf=R*23rZjp9DMmbKk+MDZ~?Lxck&WXJ@A32T6R~kPj9zeI8rBC$?Kauk=ygbJo zlv4?fajFVb$d&Ii8i&NY@|A#0XDXZtpT-sIhFDex`{dknt*lTmk@{Z+JN%a)rVG!slE zf9Ra6=8x@11BIaSxdlo`YlTfD$aAZ(@%;r#<9b3qeAP4jE0H&J0MFXs*{uSl>$7pg zmMQh>{wFRJjq-?Jri8uV4F457!U;?w*8_~7$k7Z9a*fE-U}srQMgNaRit@f%CWak# zacP}X;SOIxW(D2x^vNfIMYpv1<2QO=((hGRG5cX9qUsQ-qp_bn)gkAE4H(Up!`Fa5(}#pdw{1aJ@+B2ejLvtOL&OPzC}4JC()2 z?wv|55V=bk1mx{fz6RoVE3JTcb}Pf>NwNIr-O9`Ifq}f`9;J!=&mi7+56r;?p1nuu z?JB&jtMGGslrUW5uzakH#pBmLh7op)U;0>i2YDqHE6suIV&x#*nlJ2C%5g5`Z9Y|= zXYKgZPnAqaw?0J$uk%IwF}yMStNp0bHQw+5wB#Bec|dsu*m(dI{Eg2kh2{1uZ*@=! z0A6xo@RHM<)N{Z|yf*%}nhU>7`plPcwDNT^} zz$N7mU7qmwkR_5yrxv-K_o-QBxBu1$R<``gs^S&w?pcE^-yQ_=Hr zZT7cm1MSE9q&LVa?I@!3NwdMV^hQjt$F+ZYEEZ=xi2W-%KIUwecRkG|zZJuGlw&*% zeyd!mAA0~=9{w$?75|Bg9sM3;JsfU(SGel1V2Nc(ObYweKDKNtj`y~bfh-&ow#XU$ zDMBRs^**Wf9WOCkNn{;cNon^O9(O~DkSku{3vVd?I5Ka(p{Ve-@?AHTaJGYAy$Ox@ zfIt5y^lJ;x_)}?(ifsN9{a?s``cvtNQ+0z1B|t64WSv(X$9q*MLlL&DLRp0C6~VWZ z>A2bF>nG!|*bL0eKgsLgQQG1j zM(;bQ%TB)W4m5uU55B960_NRSR=_{i@NW$37e?2=q4GGyJF1jdO|kBEjK8bI0B<#F z?}-!L7T)!N@(H~Ew;w1T4Cm#?)kuc>8vc)zv%sxK$~SnCcjzBfW<76TqrBKibf`Hs zDg4_%>*36e7190|I(yk`iXc9UAwmhdRcO0B9eL^ipYO`th@l{ zckmO%imMtttXA=F?#lFA$J@GC1;k=B(KZ}+cyLq8=@a%`pUkJ%Vot^w3u~2Y4DU#$ zGc`??YyL5QH>tP@@&O;As7KifBS2N}F}B?B)m2=6N#$*=s==1=>sECyE8r{L)b_wv z0{Q%r3$5MN&XC5rt0&k}-r57tmhzDvYCKTvp^jrqxNjZx9B{La8qF3P?QJT0Ymw2z zQ_W;>1RV5ILuHo7Z+feX@S0|hj~a!N5BR9vAl>&-JF@Rz3KoQVd^B{UYPnWURq^@s~6Z*KD2|{3s}|x^-bo%9o5ai zsg7zV^~l{?$9DH)T#r!2%g>e(Y9MZ)^@~vb7@J~@>!jwmv9bKmD765}ll8nhO~xye z+b^nzbT)+V8i1w^Hs%jhub9{XK5+;xk5&xk`-iB3f)|H~RD8xOY8NEl_KJE&XzZM! zsC*3nX{fps_x`31Q(H2;k6bofU61!-UE>j&%umLvcW?>tvk~es)|<~Cspi7N;5AD9 z6!>}+#_C0*cLIijyJ!$P&zY<) zfeYS!in;>WI7M~HI}416*VS0~-ue7#>LEBQdQTVK+@AMOQH!x9)~2Y9eD*>|4q*mn z;jPMvH`?R>_EMwW40R>*ZR<2Bu3?(>(}bG{Kj!V_mu8~tN{#z7RlKbV;SFa)i$jc| zv(;!5TpBCqsEz%?|EkTo>3U_7&;h@3G|Q8d~fbB^i-ugBv#YKU9mZSfR0 zg=!*34%(ay5q5;9WT+kLpA?SHh#m;chbwswA5>bDO2x5lR#>K`&( znd>rDyo@rw%~Wwq%%AVFtLyL@aB#Nz8D0Z&&m1+&R?pdzbG8yJNO@Re*5+U$#qg3G zwRP8+HrN4fF*|mkScg5PEo}DaApbu-u?@6w7h9I=Srm4(HYX9c>#?+J*mhoz;SCn5 z0hrZY7pk4$YM8!I4MCnO7OKsF0}IvPy?s#Z;0IZc(q={4O1{Ld<`%>E=Ayq+`R!b_ zxxZ^!YxHytoP{;eC(Ksz)%|QlY?r6D?&FM+)*$O)+f+-|!!~KrIM0R2;<wdP=zB8vbaPEr^S6+A~9`FzIobCN24^tDGnWr`i5E<-mBzCx~eNvk}o5*Fb z`Z&~Sh--JK!lv5nP=9OSEYp_V9oIv!v{Mnz{MWy)cC9ZSv($ReX61bN_xmc|X7a;} z)VG1C#p(yn#b2{!x4@+&TS=_xGu(ocoN@0gRvRFa+Y+@wLst|3xAqu4mtgTlJib(Y zLw5Hv-1D(C%Whu$`vNr$Qz&Mc+6G8phB+V2moHPtx7NL+9%ft)aV+^B`jpztdBk%p zF)x9WtGeOry151O@@}AE^US>2a&?X;;?J*zqcrgCaA?K-zj)Dd-1OGGxEog+Ve+)( zYHuM<}u!_=1<5x!wC3U?PY?MI`$V_>Su@eCs)*w>;>+5Rju!# zRMqC(6*Jpmk9>hgTvfx}-m9d==j2SDa#bC`Ugn=&RfAzqUAv08e9-XtRZTGCg6x#v z)$#08@_n?k@S<{4$6A3x4yCnlD!@<(YTYSLFvw`L(;y?INSc-|BP1 zGE1vchXbdo)Z=U$Uv>}O7h{y(Q&*Vr8hGdICzkV!`r7lXxA9qh zttZ1JSmTMG2Fqza_id;x0yZ|(#^U;grI9urNNa>ZJGb~F(9U1;*V14p{Oqs2#NOe- zjkVisp5fa>+sarLKNO&Km-}2bY63L86Q0X!n`)!v-+wU@nrZt?&EE8sa(=*0Dc-w= ztEa#{re>&RcuqW`&EwrCu4%Ka`72*X%aZBwj1%^)hcG?42*)7{^pP1NG z<5CB$xs{DKSP$*6czN?hFYQg84KsSYq^)FZD8KNsR^%V&Db4>D8)cBIu-uHGFu1%T zQtLYM=kmh-S_iWoW%9#^EcN-V{#twXiqSX*rNXTFY=Cx#4d(9;)RwbY9y|z59K?NN zwK!l(thNoew0#F_9M~}!nzev;9HKRcSvY)%R#z-zQ(n0UC<4AVB^LkFG~kM8VioR8O3@x8;P5!w^1ZWl*tFW@Rcz$opA$mv>w7LU6CJw|Iw z@S^O@Xf03J$q9*CYg-L2->3RQi&BK0@6MMcYQu31x|OI+@Z64;Wn~1#xM4zL)81f= z8>fBCm}Eq}s;w7F&3~Mr1<5~r$ZIEPA@asGywz*kB;BL6)Bok?VSMnKc8cMx>!e9q z53iFjfhO8QF5*VXC6rYh%|Dq0bw0=MP15?~uE6t2m`WG-d|5OL+O~ z+A8)1&ra4}=%6fj7jp$Kay8r@lR*3>>ym_5n&$GmcxJC;aH$3AXKmTPgnuYmOk5|sphWG>);2rNKTlV+Ze?Jv}slDSs z3qEYNHc-Bo&o|B1gk2Dvt_1`A)3t%VE=$74F%Xcf&)2`LC9u@xnVOHdyk9R<+oYSHjTFLfWon!8w@fd~f>x&TpR%yTHQ^2B zVWgTE$@8%I;|1aQcc6G(xZSSxhMVk5JM_2__s!NOU^|?Xt$l>Ig^lNHw`EqJdo0ji z!5j8*3$(W&U0R@xLN9gA(O$&p&CSt-RdX>%i)Fq>+l5*$Gw#YveIGjku8`kaq+OP6 zp2q3LVlj*~zFCT5WH(RVq(JM7J!@hC){s!+NdX2JJICDRT0Ydpi);O5&6AJe+7DO> zJFn2LG(6G}rsIX$D-#!EzK224Bf7=}g*ozzEIjN3ZMocVqN~%#Oybu*(4rcYzUGcE z8ZBkZ6aK*5bH@s3wtsutVPD95tVA99^PH7hxVI1b4NGF!UEApBphWiAVUOjfR%$7F z0!HPoZ43_9eO777Y&9F_bDQmRRvh2yvtkE2J4?p@tZ8tucWfK<4xLYqb+_HV-V+(&14! zUWhsKgil?kJqJ(8#&uY0x9~^nkU?4^AMug)wbLlmTEJfuvmVo`hQGgFE5$va{u{8d zS@?nt*aIK&*EV9ZKH|qWVt60&v`yMBTmuT;j6JxTr)}2O!fouk1?%nup0)*n5BO1m z``mY{6R)}OiNHN>*``ebrf$;)px6W3w1qHk`fS$*yDa@QzdwU*C29# z-P^TD8BVENJG1~?AM)49|by1cQ*;*#2mi!(JtR*0n!Mb=WP-uutaSM1U>&b0|U=jIYo9 zFQFC@Vx)z7IC8%bCqi)}FW*f>x0mu6A8V65Pz21ZE6&`T@arFIlW}WlP%-q{Vtie! z;WA_=p7e>f)N2p2ztJ0;v+Jy4@6O#yw2m-cdzEOd5NUFW76?sUSc1*z2LG)D3&&6% zWN0(tQ|AWe+W`K(fwB6-cx+&1u($ZYPqk^VZV!H{O~s1dX1}&Ma4D*WN{V|FLE`Od z4lJQzxACc3Oi+qbv+wTLhQcS)?*NAT3%>Ax)(p<)9S5*Ab3V5el7$zRYN2pNpDNYX zA#nOZlxgA14{F`uk^bhO7K3z6KGW7Wb(V!|oT9w)X@81y0gCanWzWR2CJHlt{YH*ogAAp?u;otvfcXkB-4?z^3r+aSiwN zjaN=+qugPQ?>eU)bZ4I#Q?F_PZmigFRA`&saHpnIwRR8FzRg4I9Xt8!0-N~uhbZYh zZ}|uo#4+Cg5%!#oeEuWtOZW{3{iE6Cie<*Re>5LOu3Bc?WO{QZe%MUq6zp3im(3#6Ly+0ma)$~ye{=XhpJ(IOF4q9~_H1dtgo(X z9S4ADV`~GwDXW*b+^J1s0(7yLF{k$1v-p*U`Y>3q&o$DM(8-03^hijT8leu!ypcZ= z+IbIu{S*ett+9^7%P!;ZCi*d^e}L@f-x3Sv=Ye`VeBgH{P_LBX5dO8fK0)|>`v&U= zVISeX);ipE+uTAQh*R197HD|75!+Jl$LcVS8bu1X3?}mlV^fG8$Lih})r`TdB81|h zIPti*)|>oy_&y%l8l!WGZ*Hv@;e}3I8@+S4|B>asc&8`ET<-sY@DlX)zj0Z7`2@#< z{rrEIa-@yk6NaiORBsC(P5ATQ`yvVCN zqC;QjS0Z$L^U9}p(lc;ltD=+M2U5q*`c_=nzSLRAmB=U~xVwHFL&!iu3)!``HySvN2G875ez%vtkc~CwM(KylY^2en zw_abv72Tl&^j-|6{IY@i&N_)=M8qm!4sztD@WF#n>sO6MgD{d%*8zj|pvEynoG-@1 zU|))VVMoH75v;89Z>0u1iW~Fy2kYHiOhGR5v8YZ4#TpzJlqxRPfhmaViQn!HIGAq_ zMrSnP@k8`*{6h;1hv*%#DtEoM#_pF7M^x#q+0-9$L@hw>K^^fuVArX}c& z8Vp~79>P0*Sk;(FaXEL(zxnG4_M2DuM+tgA-`G))Ytwx0W5JGc*ndR(9r^b;uT9W@ zQ;!HK_iKJ*G!!I)*BzsGg9Sfe4C*z4XO7Vav#tD_F_?bNdUfW}W3kx8@X2HK#!Uu_ zQibUt{+*U`zdxVU<~+(NFJFWoqUa4G>K^{(SmZUA{{!^0B84OWtZM{r9E0AY>(TAA z5Pl;UDva8Px`I}Vp!EL{WaqCZ>K$;I?!!d=_kf-@I8@6&S_n^OnYh0vHVJoBM*L$^ z4*Pd}{Wz?iJ&nubbblH4Sk0^Y3f7%3o1pJv-FWZUFdE(X(bo{z)fh8TKO*C})_gLO zbmn6x>v^mrPB&PiJMrFA^g}Gdu)MBEGlagJtj__CChKdUTdc zqR$HZ^8Nz!yp^}g(TC#mh0GlNlnGxI4RDCg_2g3)=^=INeo#|O{g0u*;+euXEYd3* z+H8{WHwxeP{QHgrv3Q-A>XlRJIFQVDF2>x5<=-#XbLBcV{^}Bao$O)b%2GX|Zo~i1 zE@r9T#7CTwpD8B%z9{JJrFsjIa??`OuaMU))w{^jM1)*=pkxm+2qMy3J6Q>ra@hq8cmofr7(U=yt)MSLiRvijBAU zKtBx{_dmcEBbyPh3dJPzNvrgiao_RdRr=>WO=xsRP!#ks3|4#>xc<+V7p#1M6)4ve z-Z9~-?T20x*Hxp@Gd_sq+FT;AxvbzHuhu8Xvd!>YqvI2cw)}+;^-3sV$F*40VSJ|* zV&Cq{KPtp3S<8PdM1`O5tLv~gKjv#b(tn1T{pNc8O^=#7FmU^LcEy^I(STn$q189) zZNMrIQ~T0JOv_%}wn^Uzi~EyJQ27}C!e;1EHQ&2g?9{+J0Y=${p-;O9ddH3yl1bc(0 zY=_oW@txcC53uF-E5e3W%x4wpt?}8=x+3Voa{grzc8tG`TSdY`xWj{Y;^9snyA#XL z9q!nve+JVoW*2n1()e(f{(=df)T96edF^R^vAidoFFB*Xj&CR)pV22V)a|uz^eyZZ zuk)?`HSp87`pbSN>-Wvc-jwo zU);Ap_=8>m^K!@q^sAY#xu7?*HCl;@iCajnIo64vzJT;w_=F$z3z+#me$q#H3O|FK zS{GYe7dX-JUTD)#`eGK(pZi(oa3`PnS;yf$iSlFPFo-Gx)l47^yEAkIP|w&(_^gwmv6%X`2YAPIOx%ufv z*J@M?*8q+@)ccv)I>Y0MK28?b=B)~oUw^`9Gi#~rQOi5Y);98$Cw#nYEy5S!Hj{M? zT+usB)-J02PnGe9)w!j=fT@-@acv z?~5;AG1|u<863Nd23Y&zgRUP2SbNCcKK?MEJ#+K@1Y^xMBj2C5jJ4wL05RMKTm2a> zCWQ>Keu(Yy_z>%L6>r0LjI^dQxTBjTSl?$a@;wRGCGbAKINFLU?$7h#W2_6%j4NZT zO~l*yG1d&M-|6X&P)=SxpQZdF^EKhp_W7}K@bE9K@b{Ci9OmN)<&y}p_8bHu{7b}YYDYCmfCJ> z->IdRQmXdSCbA*1)OP=$_udKW+kXGw-}C=H&p*%e<~{p)&wJkUp7$*GOnh33ZMQn5 zhf2xAyhiioQoyg|a?tGI&Wz9DejMS>IUOm|^CYj;+A=EL|w)=J4u*A$!c>)ffv}+2K{s9XnU`W_aD#g#Lyc z&h+c}FGd|t#Thb9FW79Lfarti^Dkhrj1txP1$TL!j>rF!y3g_w+^2UY9tL#jN(K#NQt%C9U={d2kP}7nnmfGVom-@l)etvo2`n{U*kL_M_c`A9>*tL+v^W#ah=1b zvwk=a2HIowB34Gy?5=w3XU0h4`+9sr-hnOau0PJzWr;oXH?d4<-xJJAX2W{wyTP}o zr@k}f%g{^zJ~l80^wNJ}{%J8;;BR)5wz1+~`dT>xdcVz_iet~Dqh+J?O*MS(V(Hhh`mVTsAq9V`Z|4OQcHC5bng+YNa*BS8J34<%y1s#iGfS&x z>D?i|g0vx1Z_)AYf^=x1KCe7iAZ^;B?_}U^N-y{7Gc;I;&poJrzf{q)yn}iNKQ^3= zJ_It7rMrjpZLozR)jXo#%5lF)*N*DTXb}F#5Bkd-UpZ7da1z3X3xB6iQ8UOy&}%&S zn>8fl|A^;yvUzvGp^dEN z@A_}R`@G-viTK>jpnSFD+`9WX>zAXCdJ{152evT>UAcq3%+Ys(A<;2c-xaD&AIhI*)) zKc1rly$uOuypxUzhs&99b1-}GQr`!IuG1?$r$vW#;SCG11d(zzhB11uppR&XE&Co? z>C6bif2_R03#g!{L-4qeVL6skgG`2CE>W6eGPH0u88Zcjk079MbUfzLhp~G1T;gm3677VH~!HJM}UYlg-wux1k{@{$#TK~C1Jf@t z4d0XC7!jKRA9_5;PE$%iOKI7M2COTJmPopxhEI7kVbXBJPJD+Yg^e_fq?O~EQHDUQ zgpZFhjKaDyY_y>woruJZF@$3WbnX~Ka~xQo8G}m8u_8jVnK;()Ig+H0MN@2S!&pNX zH239LL%avhD|$~bL~)-3{ONKcN)BL z${EkD&N5WxEc0ihb_?^HZRpAMV4G$e%CYp>i0DV|cGw+yG8_H1Qff5EP?v*#`)IDA zl20PB-$wfe?MyJVv1*QI3+5UEE6u>VG4}!P_#i?R!6B4%CEfaQe5@8jqKo3Ll`vQ^QDHNw4xl6W!Mhur{Z$MZrDPX zmm5BS(OiFpp&~wQXPsA~sLgEmN`nLY%@M0W=rcBMm7z=EU9ixZaT))`$aAUmrBG~g z2neFhm>_4yVRmPgp$?W*KC2DiW0`q+HTvHmeZ9tTQ_DYE%2Klp8HU}%U&@bLd*IaL z=5S`)VCV$9bLfhBA*Fur)H^m3D7DaTcj7Jq9945>)Tyh zr3H7vZf+CX{<|RrZ(iK}-LP7NrNqp8h70bH>46Un*WJ0PQp8ikQ5}{R9Ry7g{)w)4F!L8sg^LZVx0$alUc{fbV?B$!+unE7t?Z_ z8R61^+Cnu>dm)RiVbl_=Y*~=t4hvvROQDiS;%zGU8tc+fsN~s3@!Za04}yfM{JktD zqc+2zw`BzzNPKZ#gjCMKF z)cQX@aTPs5>#XNgV3yoil-KPg=qI+ zB1I+LkoPmCYD^*SN@F~ZDk1IJh%ivlihUI(1U0&|4C6G$)+^b|nO@*>i#yu+I@6EA z7w(a46~APa-Q2?6o#~V|8Mt7XR1zi}d^{t%cB^f4rPc zYayHfJHWR9wQFqrz3<#YPt#@-<(!hs_>VsZY4-K&g<7& z2oCB7_9*M2U8i8SW0PKsC5apMy*#m#M}3-OuS$x9(lNQU5XdgI7JNO9Be651Cwtmj zXjQQ%;*grIkL1*B@l5`XTo6m-VsUMR-^F~SPAw2q$KX{hh&F2L_~+d+7bN?FtqLK9E2Q;}WjD2#vs5)~uN<+;<+rOx0F?a9UpPp~b5OGX0j z5iO85#0lf+fyd}xLKU{8hk&OmdI&HhwnzwR!i&_aV#@IAt{#=<^cFT~aA~JSKcO>! zZ#kRQPiVviup|A1ac}YU>_71Jtoy(5)gpXFfsVJh+n8PNFL+_^Cbz%P5tBp10YX>5 zO^~9rAUX)s=G01fF6U+)#pD@BX9%;{iUC3u+^su;gwQbM27(PESd)RmXRtN54iw(! zyqU)!p?cZRP)Lq+{F$8Vb_BU&Z1K(v57v5+aF}1@;%}9~$n0Q|gM~osVhkB9Gyx&Y z1`GaLk5W0-_xR?S?1+lyosOC8)?n09pz{2a1YsmDjo(cWQaSFbH2g#1Hx8G_yCe#c zcq}wC5ribOoJ7IF->fW+7%JE~LFlL)6@|heYGYu34if@}>`sugiOt>Vzw)A(*1jcM1#i}u~0%jw44L74EJjsa}yD4{OQ)GecgFcWsc^6Wx2 zdR)f*g)rS6uX8M#E~I1cy?UCkp2P9%xfwzOEaZSHNmbK@Eu4173R0tM@FZ8!OhGh4 zV&p}Fz`y=NPO>Z!Ho+=d!Hz5y&MSATx#a53o;2@==arppTX!8V~5PS8+cId)~65Q<{N?LrF=vX5XHvAFHRKss5MwhO_2 zBhh#|Qgdc}1eX|f77ED(Wdg0ScK!~KGKE#%AuNRbziWq(Ub>c$I!Pc8OIiDO0$yl4 z$Cm99I^j}C!7iaUhD`Ksffi3K_6TjE^-}i;i!u3E*(+cTb5okUPYC1jGK_RUsO4Sq zHFzIsi%*YogI34251tht5WdAyb=5(kqYo`zQum9IM;$M@qY-7Xa}>`shcJ=XW%UmU zO=0wpI3%oi%^>Sx$X6g+aTrr_5IcTY*hTG3Jp#5wv)m)XsWMbxIvJ~M?@_@QqvV&P z0?vPCO686NGwX4|#1ejhc1)B$`9Z)w=mo}|6t2<4d-J3)mWqozh2~^P4^E+zVGs8G zQHVlkfBhpSxPI*Tk09oBgY4$dLUl9sTDmuw;|Cch%a)b9ggUOWwwHu%csh9DB``T! zx_L=hNAI`H_(d238Myxo%%vmJvMa(J4rkRVSD~Wkvh1tEAgrFmYeHY{pfuu|aF;BM z_iqT{rhFO%&`6MlIOnb>E2U*OU}=?opAIQ^wWb4WyaR|yDh4-mSlBHLTu&+Kme5{@ z0(Sh4LAjBA_=iv*`hVdcLPLn$nLmVJ*zPa?K(E7w%n_#GE1xSlLRi@s)Ye@x{=X?x z%iha{1X;VaHtVN5qI$|w)c zSco(F0!V%mYg7R8s0kgIUWijc-468Ls*Wu6R^ElnC<_;Dn&%;FgXlUY);}?DDW{bK9u1)umt_SLYh`0 zq;Y|+5r!VaNg>k5fw&szO?t~9)aj_pLLP&N<80t#X!*^|@faf^{}Z<7u@H~TN4`&l z&(%Td7{wMp5&Za^WVZ8(Fb0S2K~EtpYox(XiLhigZBFp|$I1d$PeE%p5=~0y=<0>zDqH^o zb$!ily%2_CN!#(IFje7ovY2)N<<&iK3%9vPvFk6P>L)VsmCzH{ffST$7*>L5&5E%SY@a1+fF**zmoXLw*GMm8BB#Y#!5G3BFN}XF=blt5 zbi5cZSq#Ps95$-!2*yEJ^GRO`MjQm&*nOk15^P&hG>*n7oFW<-mLBCzMh}vMK(jFk zMxE1a90Fgl+1L{2B`*YvZcDdmi7sm_`ejC1jI)vgN0YM3={RWKgM zm%!_Njp69iKYWdCuu!XA(RdN|0Ow~s4RprOc#wa&nq~N-t{_&kk})Y{I;hzRE06SN zU@kod>vZI-hR8xxKd(?Mr#b54Nr7wS7=hJCOl2cJe%>g3RK<9U&av9tK+flq(`NMGu_T>W-B_O!q~q0%7jQ@} zEvaFwjn^fmA8H$M!tt?mBgojAvkxnjbN(3nRCZ3I%gSkOP3aE$eDzq{PRdFPwJ8mkD#B|3U#gUZm$Wa`l(;fMWBRSo1UvZ32 zca*?!tgS^^8fDcn217gjSjRXSs8fjXJr(&G6f3(?{paY+0JbE=*a;DNA;tjD*4Une zS%uH@>l%llhbGlE-uAAx2Hb4thwIfiX=w`;yq1lr2l>ELiS>*VIHV7~b_%2?GCy6s{o@L>bfbT&4`)YPQ2(ONBij`ovrY{sfqFZ9@me)JPzhIdfAo0|G3HNp zVZpJ+I*`}+Scr>()$3{;Qa)6zefy>z;V@rH(r!cmxUwink_YCgo+MFUIOnP?2~+JRDA!<&u zu_MEbi*fT{&~T%#7WWD#je_Lh*2>AzAnG`KG8$u~j?`?7@fA)6S<{a(kk7MEKL*=_ z*oKeMCqGHIKE^aXO$R?v$J z$O-$inz zQFo=!(v6oic>K2OY-2O*?|MnI<`~;@zD6%P)Q`XnA4+#LaF`c~Yt_+Chk+H&MUNO* z`LB#qdBKbQ>nmdf;cH(RKg8RNkr~D)E$`{Y(wVU~e`hB9jv2q=J-k@V0%MOs{XCpi?p{aMd>uJdiR|Tc$gd*{Uq{9$k%`#(n^Rh>UeYc!`s#Sx z#|d0&Y|^;QV>vBKn^)EK*-+|vF*O?62RyJSG3iklE@DbJZg}GYT>4CR9JV@U>ZCbK z(T8SlB~9*LmuwpZ>C`ggad+-dY2Iq%r|vlV6E+w_Jn$l7^KHg2J#d%z$S&i1{HsT- zaF=l}w$L{0Hg4i!E^u3E z>TZzp_LK-xZRkJ_lIjjDCJ!8IFAd3~>3OR(BHuWOgMEFrz*rS)s*(a@FYa5ZQ=zfH z2D8+L2gZFG=&uovj78i!sqbTB7fIBrIVZN%z_ysA6>$c*kiFE2!Q~)J z$J*hCk1*&wjO z>M-B;ttf`T>#QgSY4B10&PrleOxA_~F&H<4ng)nn%`YJO^cjU>T&2%+SlHqKF%x%+ z>II5bkSH!t>;=ERvK=i@Z+W7;gd?kpZ<>U&86Y-pR4sObCqkDp!!J_&{!K)n(ZKE!|gr< zh9|KnmBnhE~Y9dyZ zpGhOCi)S?4IH`Fp5%2Ggm6`{OEpg33npB6vM@XIOiyL(Kfa7^%v3Ar9^nHZd_oibJ z(If=Wsb5iOm?9Ce+G7zhYVgEa6s%mNg-9QZh*g76En>sNM1NdgPYV-kqu}jf;zCU9 zU7Cm|xFO89DXJgBdN&m(09|YWN)Mk*s!Aut}CIk$|0H9@F`l+nPa{8RzWFdK_ zPa%w5<&|uDxab#1iEvvG1A-DwQxbt-g>og;;c&4xF02GJ7msRiVdeJ-F`3MVK9OSW zCdl$uBUJ&juC8SJJBcwkeiAyPJJw6BI*S$cTwAH{2jUGa*Gg*MPi!SX zpzXuOC3t5M?|O?HJfP1`CX2P}e-GW8?kAyOG|EL__+EIUZJ5}PMI@@M&OT41L5WN} z$!d%f18@&5dYm{B-!dN=C$_3|=CM4ksxlhVKDDK_OUw(I`m7K+$3-}|`kiLBPsAwb zs9~RofjF~H|3s{(!6S`(J`+(xgeESO#Y;&S_$2ESs)Q z6YqOq59#zQu_wIMW{X7{-cUxeX5fi&USEc_$P|O{9PaQ;v6|Oy5ZjjQhuhMkOcC?a zLj=(KmqEE~^*phD$Q?>x$UTZ-h|%!7>Z2cQNbeb+dVZW9$}*3#81gov;|rO`d~p?D zri`?4KH7{+MYR`*)A{F*+4cqEPX5_rHfA9zcVkNziX(Yl8OgXvq>Gqkq!#}Ym+J62 z__Zt%*3EM%c%}HB1{WH;uYnXkWf#|o$+*baVJ#$-J|Pm9;RfT7b>ep1S**BTtj#}u z%%azeRlGc(sN6s0!IIaD;}Ko3UhEEopv^a8y9x%xw$jG*oGeD?y=zQ7!&u{we4a9llbKA$?vMj0(XcVd@U$C$wr?` zDzc$$@x2F2)L>>QJH!l}v*PEZoamR;k~j&-_MKSY*BhClLNT;L(WNBjxh>VR!m@1i zccLG*teoG8H#j^GHDaeY51R>^T_P@sd@K3v7V%#HEostT(S&U(HftZq-pBUu!w9>< zD()AX*SXlcVxOwPG4{DET;Ffo7}o^Vtmhru~Fz7m_ZUyMW6U-yd(u;xxa zAV!;GKct6nKS+;L@xSnV)*;asu{j6COF;V%ik<&4k<|2%SVe~$U44&>>u`h7;|J)N zUaZ{@;*@{^N`bxbdsQE7O;Fukjt|FA zc_E!j)~;Ss)=BYd1zfn8bXUy6(z(*_;vXy%DIQ)Fdox#_#?4t?YBOUCBXnY!`Ci7DRSC za^Oa=pW?uLd#W3SU@N7VbVlC7RTYD z{?5mkN!PJ^gw|qjg^<+YiP+j5+cnOYVt;zTzd%MXzNh!+OapLTax!P~^N4?fWnq4Q zwwyE38}>hOru(=9c$hbhf@TfXm=@sD-f4}gX7z!f;7jE`8Pr##s;lDrLX;yy$)gxR zNqr?htqFn^Bu#TS&Bv~{&`9QuFZ=*W|*jl1bYv==Ld~%7T&w@;WWfCDcdCM<55?R$?Q)PT= z6BTUw0<-Y(U{fe3jP@)&v%ltuV`V~2*>tlt#B@Z5E1DAS#B!QaL**?D#DMYN$ZHBhmvyx z;X-N2w}kIW8@8KfYq`5p^PQ#;Ji;!G*lWV0LDyKdgW%OQY0p7Z7cG8)KsaVvrr|D1 z8%~h_tn~6n@}HKLoHvDQ@xI2DpV2kPrM{Plg@>g{zY^XrExAE>x3uRs!rw{P{xIFp zaNDFkd4xAhONt0*OOuKTua){fG2NpZiP6tZDSB?9blTkRS-ipMT$8h*@ zn|(FR!DX;FR8Y?>YPq4(%Z6qcXknh$GxiTGGoL;Ew*<(~od7=~@EeQ0e6`!gVD7F=jt^ER~vmYW@o7^rzIQKHAnof(zZ17LQT}K z@TJEi40B{C_5thW_Caathp!p&*D3bu&9`EkBewKijc+IhWnE`qInA|jRJq4#UZIr# z4a)y;mbtI49hKm4l@O0T;9j|metpdKGKW&O^BbxMb;o1Q?v?xLTk#q3M4u!6H|CXT z9?R=Jq{*4)JRPs|V8a)gClk&itcCwy=6-}v64rRI+KUkm{0(6q{v`+pPIuwFB?!mE z_rsT}IBzN9-8@*wWh(w=nRzlU^wi2S+kw_+nfqhdc`Y{|#;`lH+YGt-_BFd3)hTFFVoMyFae?)#~Cs2x`IE z#k)v{4Z%s>y=_?XujuZ5Nrz3>34OdL06psC{Uz5%niTI1T@xV*{gIVxDUBH5y^P*f z6B4``k8g%nedxUm=V4JFDd;Yt#w;}vs1d6+R6$1wHDp7E0fjQ%a0RU*)PO}LDd;Yt z`Yd$>P(4;{q=Jr&^q!4V%I>2SbeB*F8#fxL4%3bC#&^gpl~6F#ja5)8p&+LFSV5^D zd*eq`*&{-=*^p!e)@FAJ)nY@&Dd;Ytnrz4?3c5?E1{?CJg6@8bir!=6#sgJny3bHb zbv8~#cL`Nv-6tsM2q7D5__=~s5vt0{PDCkH**rp3SlLNvQ5CkGP-WJAvVtBF3S{%_ zKmn}b6a`%*REdq7ifa9t?h6IYBjm@bITW;=P(>D%qM(a}eA$px1wA5Efu&9Z!Vj~3 zsi0L~qRetq)O2slJiOJ@+ux@p&>{s%SNwf$d*d$Jp1M9Q-EkoHvXM`De7t9E?1TGd zgQaWXK6Y9c_l@v5W`yii>*6yTXgi@UEGkw(7YTJ{L%J&HQCFXRIB(nD4Jd|q|Y0WGB~1AJs$?q*j8`QUeK zS?|FLxz&}^1jowBn0mQGvD8$ueCkTbG4x<%x zVl-0LVZFv6WiX2#i`s)&^vCekW?{)b&$(Js=r|v2yVaD!Kk>n0t%el;sZTk4Tgj5g zBXM<>{25R+mOR1d24pAhb7ZZ`A}1oS3X7ZsRGCFi1`1@6b|eX4wkb$biCLy1(4Sep z0P(PG_i>BIBxTBcuUIR`9VUufyb+cjEc1F7EmCXSi-@yz6rJ82csB;_Z?H^A9} zOFPjd<)q^4=Iq9m#I#{62>FMnmE5PrUZ08C~2YjEY``XeUXo!lA5PHt4tyECzO3O;zu&uSq5&<-Pm1Q07 z&X!$mi7fl4hMoesj0XIktSd)tSB$78-moZ|GAbtuuW!YqQqU3L7V> zYb|zcoaokBihv%i1I>?E_w@?ez8->7!n%KBIl~pRYT1@iK=ZPZ;UO!#0ltSURYi|B zSb}hMqRK|gSJ*MxzR~g}cb_%iWQoFy(vD4*a~zfd-M_Uc_Q;+smPS}~mu#_A<*}() ze!Ha#WVG3Kc)h29b`VH63GvgMIQ96Bjg~Cc^!cuE3doWy4fTiL3b-j*e7!CBcKn^3 zhVLx3-pfM5+^WhJ%0Vz8Ps&;OMSkh`Y47L!3eVI-|N2Af`<>-3@11~BTy;}ns7{L8 zWvS2cz1y(qyDi=Ik*;cpkeuC?Q@9?qeUBv>n`gE5T3P}P+iR%>G;gnEDmG!t?X#@b zUnS+2lYT-U;ybad3zox(9CA^KoO97q1A7hMU$o5Uevo2+ zwsa%K`1K`A^|ImW7SBPkM#f?|#TxX3(fIJzQk8L+Ej@AE^TB0{hR1G5-z%1SFoE|n!avJU+E4+pp=CBIaEz9wJ>#pmThIZw|wpl!N=kxs-Su1VyYp>}kw(-y_ zSjjX^wrkFu#y&^h4TQ)FL2o)p_zLI+U~ zQGvdy0Yrb!m{~7ejG=$QFg$5ul8QWyL z6{ndZ@lC6^i9Rder1BAQL?bd$6PyM-Vr~n2vQptOcLGI6fa*xfh6;%Zl#%#IrP#yX zWS}r5Lk(mILMPCB5jHfGc<)+ui#uBBurr>B5VWPMR&5CV4B(ET?r6wSbXXFag6aY_ z$+kqFiMAw2x47wNXM3$Ph-eFZ@;gT_IMekxKRW`-<1(oqhbKMFs1~h_KrJL@HZ@I9qgsNLvivDNOxDl|CYD9~w>KP9g+)0~HN?IvvH(Wr8`#T?1kjBxav* zr^-=j1j6W*n(@eCcRP^lj{cbrH~nFpM$#D*{kVt>-@&KwMXEluCk!Dk&?daOj2Cf} zZR7EH5QjVy#U0(<5Izz7K!)<%SxDNm0PZL?&wNST(VmA~%tQs^4!r&x!6|%08vC;V zjas`;rW(KUAbtd)=Ftk5z=;~*L=bU;!@u%c2YxXt#x?-&*9D5H)xZL@m99=iqVK1m zY)AshdXp!j^9z!QY^CQAN&@L(k>dc-8|F-I?wMAUo^4l02i^rqdw{MBEae;BT>+bd zKz|J}`>gwcd+u*ZQeCA_lE5bX(w9u*a4qVkKR7q5F1NIxv$)C;sU}HFI;%w{{P4<9 z9z&9nqura`>M3Hr4PJa6%wxD^!wESh1ddR|8zw58W3z5seC;mwnlGVHe0j`^JBG=` z(;QS8rbLQ6MsOHGhfxBE+7Cp3sB}LNilzurVK(?Q1)hK4IR=x~aX{My%n?(6R_CTU z%CH6FpPYq|4d8O9Be-KtCPID98ly7%K8i%eCK6Blk!WJ@VDOvOzCQ|nh8=hn0B%qk z4n8@JvOkpyY5g!$O5-DhQ(_94Be$^Bk1x)K2A&IQ5RAnr%uxwRK7-?nYjp-O4xl zuiLAR2O2Ll9=f|JT%cj3^cF_PDP%(TP`&6L@~PePcl}~l2Lnb1-c=bbruvdTpkLEe zX9V1=R+tAwDgubK17tfMPU;wpt-2T&G8-dlno_4Au7J(Rjp1Lv7X-Q^(TqOi^be z+~A|U^uZnVOyY=xsP z{pTvd8U6}mjmjz=Kat3{naZX|v?E}W)O<$v&uACR2Pkrue1wKoqQdIGod6Yy0|)I& z(P|BU!@^b^s7svQl}|f@whe$RMnDiFHFbT)gNLWV!{e^02QB{#3tdFhP$4#Qr_+)^ z515EClLhj{)I{*oVTYh_PiiEuZpJK{Vfy^&K<&1tvg@7Mk4-+|{UtIE@b% z31o!la2Nn3DvgSk$cAxD`fsLU;bNw`iAef`^Q`J3bKeiepf0kB5kVF*{n2WPN)Y1YgR_rDpXQ)rXwEYi90^yLBUM;z@-;J7|M3a3{H@j+omKn?^e=)a!M+0%2Yy0 zT@&AsmY7K@S1lP@m%v{%YX09{4aE*cuBSV4&x*h#L%3kWE+gtQ0lX~DhH`B61!VHc~GJ|>_D zlui>-G~u+Ev$PHfcdY}q+3HMJLtntkQM!9acbah`$h-jy6$-HEqCro#4%w`JcB}yo zV#vfm^r3a4eXw-=+xZCAeu`4WUk(16WbmUgiiRR3sMs#*u$_e_yT%MyLZbi%q`Dme zOL3+WVke$BwbQsGPVHW#+K*JqJVYgNPf;vQwnqvK-iYZtE4-CX`*y7;NqPs zwKT$Mfd)0@S`0uhBQK4xIfU`2t^_(Iy|ol@jSgB3AU)<#N{ebUfs~a1o(4s^$*=?| zNTHKRBHQtwmjSI|Uf24!WdM(IS0XPc$^xQ4RG0;X(ka5Fi&Z=9ZFNkNNu5D8YvFlo zCGZPY0%>+vccc};^dB$IB3T5-E+aWAE8P?zzQ3(xpe#|8YWhS^^az>$ zS}HVCL1alOmj8Z4qj&73ra$>%`m37gjod45p1&jVf9*ER#x9Xhu}wiC^as)xs4kcB zpY-_0Kn1U>CEdf&C#o!?H-!B0cBQ?5)YDd?Q@1F+<^@&{>A?PHm z0>+D}W_1-1j~=^;SXu=TAAwxDf_7ElqyBNN04N<+0BeE7)B}GitBCO!ITTP^of}hs zz#NQq-2(i&KaJ7J)K{Qo|0|Uj-l$O`ERmt!>JR8Pld~e2bfAsx+w_srdj2 z?;s~8PhyE{gVD8BrYT}#CBJy!|+Fpvq>_tD3OxsJ_ z5K2=QHC5T9dXs^I-s~1)t;c7 zN*nD;KcoIoFtgryObXPvnn;Cxxll;|n`H~_J#ns`C)J9B*pTgu(O2X3awS$>uEZ(z z9hK3lP^77gHA}sR^`4eFJ8lCA%0eA#k6`!c7LQF)b(x9TA`nrqqJE?l&&%d#J{cexoo9G z()S$J6RviQ#!@CsOdUl!Mirev%&{29_(3Y9qUI4>iHXiQ69*ClX-vl}iy4YV+Q262 z0#}?xrq^Fss-a2r^)}vRqz7A}h={{3?qX4+u4W)Us3ua8u$eadek68c=|W`HJnN!` z>K+gN67>iE&|u`y(v-F=6k1%uR%#ewgA{U(oxT(JWo0dBrw@8VAtFj*Fm<{a@u9C- ziv^B4Wn+zFR~9*8|8bE6{(`#bzX)X@eq9U7Sg8Sx$69YKXmtsWm^zf!IqEb`Q}7hT zd7?`aY5K{62P++@{ASPPvb3}$Hl^W|;!ZOhi)_Ld9&BK|cUkvVbguL{Tbyed>>a88 zvI8C0)}W-p;mmx`V(l4q^qCAjOIA02?xBTp=ojrwQFfpxT~q`uo{~QU18^nyJ32|U z*uYP1PWo@Sji%<%z71DC!cf;pI$f&gK?a+IoD}oLJOk&GiEOV%My8 z>}H{*C%-C{H7T;Bht)`buKwbW^57P}*4Y7?-JJXA|NA*3!Rx7q>SQVB;W@aeN3205 zE1F6#iY!Om?ce9fmj5M4MmaA^%i5`y8w4EZa=%?qa%tGxf#i+^%ztXJX3V%}m8Lwg zEMI5uP$-Ll8tqkF>L&mHE0mUX>~G2{4YR*n$yHb4I2Tdx#{ZLl<^M3fs~r3Pb1O>; zvi%JK)XMOVh4LrBj}TAzuV8;S;P3qh|2FgAr~PXM{}%%6|3=Z@7fJ-gWERS&0J~g} z4SW?4{tl)zmU(YL3wJ)HDOBORyft^Zz@b!o!jN1t0+hh67Rn6#hSN2>SoO&6I=+OVh^vO=Z-| z()j-x+y4jbf13cRAkCG9_@iAP={fZ*y|z83F8`g8~7Bx9%#Ed+#Zd ztL%RRh5L%+Fc(DcEs_@>NCx99vB;JL|T^jZ-f$xTw`eWY8`);0h{c0Zc|GSyu-YTTD;CC~>O(ew;D=R-Q zlCJ|daA9)Sddp4zQh52o<+i&5Iak2?f5=dp@ol`^mGL|3FTPdmv{5wgD~x@&PXZ;oTp|aor!-<&|)p0(?msU3eQ60C(`PQRBvr z9GFDre)!V|@L|H*y$bw2x>!v0f+{}dPZ=f9V+?Qg=~EhFgJ13Ac! ze=`9IFTkdk59Ih)D&zzI9Z(@kM#}tufk+u_MoSZb->zKy{EgrKcEtbG{cd;sH~F(c z%pJg05Rt+?wEu;&|E2)q*1PE}ZV%=BClBP^C^VjXD2D=5>x0nx3FRNk#{m6&AIf3= z59K_#38qyfus@V9B4RRNe+4yy{FGo&OtHLle6hUa(_;Bx-(q>pC&ls$z$o|$gwIr{ zHlkP_Fs4{8JE~ZI4Dc9REdTm(vAla+u^f){9flXn9|N`n+>(mrP{678i{%`^2s=Cz z6N}}=fFA)L3@w&t0Db`Y4l9;_0yOOp_^4RU{jgZ(ffo)bmd^p60lX3RDdPVHIN*Zk zz_kVz%ToaENb^46WL&Ylsavsp)&)+~OJI-bUMyRB6wCbpbKik&J&Wb%Z^6P|#d3oW zisfMd)<=bi_+pvB*$@*c_BfJLOv0s9i&MGtmP61~K&de{C$FX90&pR-4L9tvBaan+0;3nv>5Y+Gp==HB+ zIcyR74Pcp5EU%b{7NCER0uFv&Eay!umLECMce9G+!GJFT-0WhxE?^j717H^jdIqRB z9o-0Mn1-}~6@a6FB0%{W#qwRiC+XjRFC+0A~P400WDP zXI?un0imb{CFv;oHcw29OM>ys|_-16c8OiM%nbL>>d&aYc!2 zk6&IQAIee#qn4G(>z0ptKYDG6 z{17jlFI!zAcL7MNO61X7N@OFT)9e!2AK){yL_U^YB7X*`4$#jik-HTj4WMa3iCu1; zS0bOvFOl<4yn)^DS4V8M`Y$DG=^HfR2D>fZBkHfYORr{`S|*6h6ciMs6=xS|aQ^!Yu&# zc8UBgfZ{3ta<~a+0#60l$ukCyfq)i(Qp$2~A?(i*`T5flc@AI_AQOJ-k`xzCc&3I2 zlt3PeAqRj`VkhrvJZKKj2N9F%EMQHk6YkX)$xiS6~_t^#<1 zN`C+>0Hgv+E1@(m9+$|ufYPv^;m!nfcZJn?CyvsUmhs{d`v1nG68RutG@vxH7%kck zm;k7cmfwC-BL4_D0H8Ef;ZnFK0=ffg1NMSr%mq5&8aLH23QxLTBHy}JBKrb=3B2N0 za0TFNr+@zeUS27Yh07)KtV<;_2iW>^iR_L7j0pesmlAoH3u;|OpQ9Wij=Jy@_)FbM z=S$=|$hYxgiTwQq$QR)7PZ&7>dwcvVWk)F{7ECz+(Vcek_rD0bZQOFa{(7^nmB5)W+liFS>*N4?;m9U}I^arIjoO%S3RZ z1;Bv*9ac~x_a|X2dP7L+eRK!7Q3p_(?+c75a!bIaP#RZ??_sDCM14RS2@q<3Bp(J4 zCb$5&L+&r$gi&~;%bx%|^R2jSm-~(jC)=gYQrWK)f;T>rw*fL;FcFxb2H*m~vgwf= z14sre-oz^TSr65Dgyev$gdabW(82jO&`mb z0olzS%ZvX3CL*5Vy4fG2ZI97L6}ABr3dA+3Y*9^XB~34cp3x%oEJCdlk=HQs%JZES*!4&26nxcwLX8} zz`Sb%U-e~eYg?=Hwu)?IZEGz)(T^=69OTcAQn)3671p*^vf2Xj<8SV4%jJewM1t;#R1%2p#SA8%tn2Z4^YHoQUt|8X0u z6>P0uC9qna+z@%)S{d=%(_M^#gN>f8jM_sr5EP_!bBn0P#s-6~ZPnP)U~3~?{CjzF zCOh}J)raK=TLbySLCjdk+Jd*$VV&z(TkB%$<;lI+xp1_9Qypt%-RRIf`D50;wzVR= zU&rdHI}ZO-c3`^Ik5ve<2Jq7xv!)@|TDpm0dGd7pAdc0-CWTnb@mHI(`61xLwiawJ z;`!+<*}V{J4}NrO*1E2>j&8tbdGZ8i?hZPp*R_`CH&0+I>LUI4&)JE(NWVLU_-AE? zdZ_eN3Yf^wT|(lZdR7~MKZPx-2MXuZvufFB{Nw#nUx#?|(Tb-EpPb6}*0WaET}{oC zJF){EtmWp{x0csEg?BnT@DZBOq`tMHE@oPu{0Zw?tDGMjNB%kRucdgfpgvgO_GO+d zvQ`1*eDTvm)*<}NG}fa5y1l;1_##HUQ}nOWAD-zrU1uhgz%Xf|ljU$5<;X z%IzL%ZOpICVzWZgv<1uAPQpnmn6aU?l9vr#bsQhvZBzW!buU)r$=|Vh+VT}yTtjOt zAG20vMZ|ivc7H>wRu{iE55GC7Q21LzYeU^y`0YvqS!g3`5Px$mQB;XdX$0nlt;>@~ zuz{bUx$7E%jM(+;b|X}8`-T}CTZi$}H?Rqf(Tun)Y-3|IW3hrOdC@5Q4nJCZXA6G( z!di(h*}^J?S!;E;y!Fk9G9gWQ(ar4w!pKd3lrIQjXA#zb0!k%wpemUZAA|V&Td7&T z^^)Lr+mrO}azFi(VCV&85COaBbB258nwc`RUKxe5xgPm$n` z#9A}~v9|A6zb0s;=l5(z6No_8_jz(4tK1ZQdZvlB6CbyeRcdM-$*1gMvzkKuwR_o* zO|5Npe%CN0*{xR)_t0imKb_n4JejFtJ+v9bdh~DXi)I*xi+^LQn?a0|^77<+?A&88 z_fa#*PGEkXjGwY6f4y*PMgBrQ>l{w>6tI!u);gNd=Xq>dxHVW4_Yztv+}d5|=a!GP z%dHuptW9%kHC-=lzC4pn9RmNC@bfF(*~aG97UdGkmdB&sxe;LH+8%6u1cpoEhwKXB@t-oUR-nCC zO1@0}O@DC!&+^dDDXeoVXpitO@$(`mdrn$D$w2}X!p*r>4_4F)S?4xZUp^;`4QqpRn^)w^|6&hn62sbnVS#J%<*jVYm~!RV)i%&4+3=ra2g<^4 ziiAIUZN8kWs@RA~FmBF~$euUZwV!wjCy&x%_j!e4lki6l)g^5ly+wMn+pZ z=sbTVMw#oNSI$OT>*@wv#k~l2tCs55GQaky-0xbxoWZ8XA@lp~LG1Wj`EoHkmw+L? zustS}usdvLds0VtSz&vO%!GTaP6u>(ul#&Dn=KDVqsBm!Yc3b&voj^-g5AeghI|yU zy&aJ0W)XYX0j!<#XTBVvCT`LZ9LRc}FRx~EPk;kS9j)axelPQx{-L!3%j#&=YQo`L z)6rT@lL^O}j@Ej*`*OZqN$ncH7!ZAxE0E`_T^>vRXud$MOyyabBgX2li_jFv4M=VH zu>&#COA*=vrF{3@RWVAnjPGQvuBo9bV4KJ=iRc8i9IY#mm#K!vN1Y(OYxM;*3lUS- zkUz&zfc8$k50dY6vik7@jEwILjiwb@ozB*7y3ytW`M9b#mUTuayeP|#Qhb(`J?xCm z++U4V=>j~bChOJ(;oEAm$z3qPyEQJ5LsgCTOBW17Q#gA_>D(e&l~}Ou{znD!9d_ zyFnd&_XQi)&DvXcYF>eSnuMt=yWY*}t4o|;Am3H}-tR+5ZH(1qmIyzt}9o z30v6S_c3VZY$=c%GV>^FIcA7MyB2RHx)qxuJPvekhQBp4&j&q;@bee8vdM8!IWr~p zbDXsiuieFr-BDiTZq|Zu${sedJLGcw-U9idYCU}4o#b~PyVBj-Lf7k90cioUS?cz% z+A1uD-1ep5U$L#R6!SZ~H>5hLV55 z&js>+HZYxJq$gyg{M7;)_%xRO=m{A}xXFyYFc25qE>H(vIhNcDJdgX0&FY1=?9OGs z_k!UW{;WWbQYdkAO9Z|X;^sCUVU(Zn`?fFUzpE?_4=uvVx& z6A@NdW}2(FK|RevSm|6%bJ1~xWg>&v+ZxPg>R5~3;8>iVjU*guVoQ5N5^wt8@SK^+ zWc;(YwOqB)zJ+psDmc;@7(I=5X!uS>?a@Push^K;Ha8=F4fSAI)}aq1tA<~pJWZ9< zls;%>ia%T02j#Eq!G7!miBIg!o&oEU`rrxzyLAFBYZDKy#l#oN*V(t8&G0cgkCj6yk8?b($Bz&C9s+dBaDEy!f|20+s5 z&SO;uqCH8tL$aAY7-999Ul()i;DNB4HqU2U1|rRZ_3R$7E^AkzT*Mxb?c8b*Bs6w+ zq5O;;SPUN62U#ograf%MAk-bS=l{_4HE>ZC-`~rHMI(_ zXlP`FsHkX&sAOcMXoO^BXy_p&LPJADBPBy4BqJjuLM0<3L?Z(tSO{T-jr)Ahy@1y9 z|MB_gx$~X(nKNh3oOxNg$Tao~YFv)Itcpmp0;AI6e6w^+nWMv2K(miKPl+qgXJN&h zuDqQ1b_LJ57n`M4MGD=8ThL#kA>k;a*LTfWj>uD6U^qs##rMt9PL`@8Xczp2psRE; z9Obn8sabkmN$;O<#E-*IXs$$?+wf2J|#bR*IJW`zlrhrDkcIqCM$WLkX}}wMf$x zWn<}TFrl^3BE3x}85r7!R)d+s1u9ytnXYy=#qK1T)T05#2sEIl8BLFXxC|cBA`O7p z#c)iBK&N>OrHly84t3tcEz+w>Ii{^aIaGEnP+;XjwT9jLQ7zE+A+ zwEhG~a$5_gti+Grfr@pGEfN$h`H$60ubI%$9b2enJcdbLl*a7&5Fn~CEz$xG<2%S| zJ`Yjm#;+8GG!Fhg|HGf!v@67LSAs3hr>J_j_9#;>qYQYsxu9WM78pr$t@D@s&VYrP;{im z!qhNM&S{u!&=XKAU0Nhe&hj4@B?6eE3!UWHzAjYGu`R|^SER<6QG;BuMa%*4$9aSxOtfnYehpDG%sdW`cvrfx zj*C5kn%991)7{7^3JKJ^k$;rNX}r(GmVe1wA4u&0U=PYkDv1UG^P70D4J}NA71uD^ zRCq-oc%NwIGGqe_pGeJ7sAtSX8nj+Bby1xAy(GDQHnTAw0K@7}{$tD;Sj>MgFJRI4 zVJ!LsfkgsKQs%zg^%|{98Qe}vQu6XH6=CY{!*uY=24*&in%8R_G&&q2!fHnTV*^bs z{9GrIQ?zEfkT;2zM?)FaPNrSaXgaG$=u9+t#q|-Kgi_YTe@A10Rm0szlU~F8o98GF zq$wL9p3*&Apcmf!M0|vjH)uSBXfL|3LF3?3=+*MC^=G~x=CJ!PUPF}vtMsBl8fx67z6NMV2kvkBEsH$QzM#t&V^YnkhX3{ zItB3iLs|TMa ztX@h}UqL0?!zlC>s6pw==?uH;mQxL=I(bElbdqNN0GT^_3l?Z~;S{3OWAty?g` zSFWU@El^l|*0f-PU$!5U-KbYlsrYp?>s7=ztiyRKMFo75@q#GIc@>pQSWo4zB3^V1 z*q_xjSJ+@F$99pjGRh}5+#oU0`pwl@fklSl)p-7^r z*SN4rEz%D(>T&4jd9T6NW3!8DUc<~)dx#viY8=d654T9UFmS$v)y;~nNFeP)+O-uC z^&jFC7kxPhrN6utrL_Kt+JFlYACc`gbV>C`l(9|YV99*tx){BSm!!98oXmsqU6Rdy zE`sMVx&$mV{#c9j7{c}Pr0?sdYh|8fK~aYAneguuI*io#;tEI&D+k6pG%vWrktQO~0eiITr50&yZ)~nbDnj^O zqU%Umh`mHzObafN?duvRP5gKFqz8w!UZPUrcL5f^jxfpJ(Po4Z>b|24cDH{=MNDnV zsOEKz!>q8f7HI|N!^-sQrlE;KtlUGKPBqfW`yc+?`$qVyzNc9U=y8wlDJlVqR?7D+ zu#3w|^v4OBX=?2cEJ+UuFqQ~!U`*9tp(SsiJkeKa2h*eHW&D(3qd#7f$kbIL8cOrb= zEjq=t@)p(XM7+q~$UF(utd873?Q`pTr)ODdUXHqB3PZJAvBD^>qm4<38~!_GB%#d` zey5@&EU7F0z)3E}UV){ol{^v*2w(RHdB2IFnO1+lz#A@<)zeYNts7eU>>(|%*Qkpd zTck9)Tnt^!br+OU*FRfe=#fo)D|SJ?WVKMnE{(ToNoxz;*rl0an$XcgBj3V@V|NQJ zeM|G4+Eb;M1Z8FS(_5M`qM4b#UlHIgEL#qCFw@h=k(!4eV4w+rdoQq!hny99KM=9( z@y&mX>41d*yMJEy02U0aPo>~+e!zl&4djUUV=SaMy*`XHjRqEga56*pnRyotqHmHl z4+g&Gj%Tfk|LDc?T<>umLpr9f+p90kr%bs1P<5 zl<^J*LY#$O`h@iwE!})aGf}OF`(iJ1rNAzfG?4sLFzE#j(MubZjhpi+V6xbUsVfDO zkcUY2dyua|B>z1~FGZ^dbIJ>XJ$p2ds;l5mP*!jadtkb99;T=BqcE&>d!aJ>DXwAW zW^15I4kQ1)8VB$8VfubkG_!^m{Pe*3Sc9=ZU`_X7JodtY)eobby&4x6JKKNvW)}Rk zzy>26|FPsQ0On{*J$p5p$6ev4k$sfTs)L{Be=q|u-}^A`7^}4?i>;p4uhR^(b%i4g z0S5La!~uMOh1gQ!yAbV#@Pm3R|LO354EzkXbnacWqwjF4VH!Q0gj9`#eeQ65|HfOQ zut^p$9LI<_6~k#3!l;c1^M;}!y^#t9CeV)iNVZ{}OT~~#v!m;&=$mRgGT#Rt@fbmF z`@jR?BPetq@NBGN_aV>95p)v%>U4X(6hVi2z%xzzU?Zy>NrU!d?pNt(;eLdR)Y0bs z8mD0~qxAiYIo8%9*I}svEJ{&|O80}`@<&ngeh9C6;5TUIQ?Nm~lg4>llEc3{#yJY+ z)&F2#z~X`RO@mtG5eO_97g%hM!@|0FdZTn0?TtCAr0JE2EY4-S3CSlf%R>caAp?kF^qxraS#{M4p@Z)El)#3 z`;MmFX)w(M%Tz+QVQCLJ$HnUb?gH@?T0sK0k`8_m@H2Cy zlStns+VS6MWx_8G*!>)y4=fhj#_zH60>8dS@IqSk@Jod$;DE+k6Fx>SO#sG!I{fq6 zfO?Oi9S6W!$z$j!)A})V=>W_To=$q$?k=yv^lWnw({r8^%{qwkSdIO6eLXg!e!vnr zQT%Zm`T;9??b{S zji>1u7*#q~y=1AV=b1+|78IX>&7-P`dP&{8myx0IQKz`;rC$`WIq3t9 zNBjq+Q)T@!I271T#o!s0iD91SL8meyR+>EY(oDq`q|d|@U^bNo9pc@OsWj^lIw$2( zlz|q^#JXwGi?FU9IiwlADq{M*p67z4#X`RQ2g?N(5A6QoR}3ufKUgKO*!wUY(yN!# zBe%og`aJmEKO}XpV65L4p7ZwrmVF<_mG=XdHJx@JhHPw~PA3n8`$HbP$5EV57Q#e4 zMuR@o*qfK)J74~G5L8&21EatXF?0hIhq=cVRJ8Xy7~geXl<^^0$bAM~U>Z4tZX=SA zJA=%#u#RY&@$Z7SBThZAzTV?PTD*#MX3#u@7aYAQDoe9U2=S(CSx7I*o4T^Va_QcB z>9*3lu1Bzq9Q?Q*d!h0k{F)?eDqQ5D^<*b zAg2Wu*wPF;3M*pX6MF2yLTPxI4je^30lusZ$dmbxM>TWQd2qkTE79TP^AR>x%HXcx z$=#OT{RsJlJV|Fh0@v!F(n}w+X%|YuM{HeuS}&bv>*P@K$;Pt3cnJbje!C_|vrr6QsFz^em;bnVBez3(_Jw4_qf;`FOoW=rVfwVpb%QLP zfE4xwlneigh18aVG2On9+>T?fE%zBkH>Swre17B^=)8(i_1)u|mFnOiJ&dOEF26Qc z6QGV7jA+#hdMQH@ zr|BnQv50(u&agkWCTf@lgp&EkNT)QETs}rR+NHGQW8@RJloCINf5}oh`7!#Zaw(M~ zoP#P%uNXJw)z6$k){Eq`7Z-WnD}yYy4x=G?i0=_b-b|CiXl)+ShlON!9z|jGOIk_(r@)UPtM$?tnsf>Lmw5>yIQ0~mJs?6ag(=K?^%Mp}G~EBN zdpKF2hW6vWh9;jzV%oK|!mHDOaulsB?u^D=QwMjSRA!!!dmD?SO?2UmX1b;w zexrc#AL|Zf@UxDgA)lcPelaxtGn64AhC)B%DI$jU!mYM?NiSVu0fi3!jN9lXYW_^K zM5uq6{0lfdtWyOjv-1|cns?q;B`HAI?)%{`8)^X zlwSh*pTqIClmxvrgDZygmst)nd*Xp0V@zl;}Y*@{O4s2 zl*?3zuqlapdi*J{wC(5IOFL=$=O{tePKp9GuidG~&l}P1OX!00pYsB07j=D(q~qQq zr$RJk-CH!T5bm^O+ENJKwtAb+z^#dYTi?GCz~d|LUCj7zQwRLis@-}ii*7E3{C)fj z%@iSIH*Nj`Y2@vu!(X7eYE8~@^K|P%I+khOYANr>frDp zY2;K4+~Pg*F9vS+9&KjoBfA~s6DLUoBfxu9UW|P5-Xq~l_j!#e zbKG~31vY(U&8gr$C<(y(=3ef`GGOi>(2%b*Q*C46Cu>Y#jb{-@2Y1kfY=q6vq-OXDC7Cp+1YuQ&n7Zuu;d6y0EYJ_pW&jQ; zhkJG7zWL{Q%+_Fg2DSbB_;c(AOG&AvlYcd=0!di*|gCinnLc zNx0QsNA%eF$HZ+*e}AnRA!Ht*As3;;Rve*)7dhM!+IkV;LXPUCua&*p;)@tJ?MJER zBF4P)N0_mYH~+cfU;X%HRNDMR!&0Xmf~cD>bRcIKXLrpQYaMxa37-$Sx_&h zd<#`L`#7!r7V+G3_1N;4SCR$aLS-(6TVSF7Fb%=xyO4E)+%7RQouuWLP&e(zdg&T1 z3&h~~=n@7;*2h$H32l&&NA};L{AHif?C;PP(PwERyFJg*f$uc-vx3j{$^_J#HOZvI zSfK*zV-z+WqyviwHVxk_J7T~f+*kR)v(Hf%r>FXy9LkWs$LBP!4Eg34((W>zjKAO& zv25!6p$sxEsYtKvUil8vE<-v&NT>Qk^f~Z)#q2-xduR;4+uc(cw zT?uJ^03K9A-anw6sbAC9AK3qEI?TAmMY;s44lKorTv;wyRmw_mTv%PAMBsv18J(;^efO5>r8A0DrHq`d8MG{dL5* z`khu?M?QhS(_W@Fx2fnl+Sm6s)m#T(mNbz4FTk@K$^RF`v;LEI`~p5I_>->xf^hYJ zvYkOg*3}R~#Z5H18ja-Hj61~2;p&&Gp@dbnvYATWi~9_2Q;Wa#^h>p7oT(Q+2K)*n z4Ikrwg^pCwu9ueZcHD4^{#D~?T4m7FaSmZ~7drW`FsJ8t>FJ>wM0Wm1Pmk5$gkK&$ zR`7>skDlJbhnUx+m!4p5!yikC_)lTDgy%OLDjatG7JLW+0%>kw5{VRA`{fMtquCj( zMg{VRpE?PC0gBw%c>{~BG*imCf%eFSA^Zl$S-n}SRHX3Vuv$#^5o(%Vi~dkq((+n_ zt9*!d*Mfh1tm#xO#*}I>-D2EhFb%p1cl%)SzKQU5LueIK90A!4s?HtSiq*`rlW5u> zZfXXrRW_~C9p#jmbQ9$$9!3tgaO%t5wzdC|win8-JB#rI>>Raz1|HNe!Xcm6Zy`di z9UZ-eNl!JRRq{u`{zX^py-6<@k=;j7+bt9%X$0B+hJrSYpxM8nqwVZz)o;MV?P>RK z5OA?Fg;ni0%&5tV!y)|~B&dCB|K35O0NIL78gA7B_~qME4<}YpxY?psri}dm(_l#u{5fm|BPpW}#%4cVt8x?_xNQ4?U(9`&AMjjYnL28#!>k=X zioAaZ=a!A8{lB9}oE_=h@5s~Bk*@#FJ?cp2x8ZJbB&XZ(_Z&n1OtZ#N6ytScX!mVM z&S)pPa2pNbIhGnh)$wCnad1~2ajt)8yaWqpTKfm$`8w0?KX4k|#)W$Rz({I`C99s7 zPvdDzJ^amFDWhKFWE<()Dvd!|Su%$8syu1uG5fhv4Z=AT!+%k)|LmQ@3yG%d2AO?x zQReGvgi}o*hX(Gj3FP0v^_W1LnFhMiVc_b^Zmm!^O&TE)>KY&cBsc15&`h??ocQm2 zWzPQ+{e<6HYt-1=mj1_|rMDOSYbVl_1Ts)nwYp)ORvv{0RvaJ-HR@cAVkB<&!^QlyjQe3JEQ@pKlY=Nu5feO=z!0 zGbp18;R7FU#f&VU#BOSW*~P-AReFjh9e}1X?k|iu?M(9j3-$kgCT;u+{bM(aj{XIS znK`RfdP3RaZTt&njnpT}tr_8rPtszhS+i+tGs>xYiVioUd@)Z^c{5f^Nq*$g!k2KK zZk3+zZTG;PLZYcKTW)t9Fjw$&*weJJ1@UvAru_&n*vz3KP}|5kt;!w(`ZKy$Ln%P` z)H&3{;f!<0Ne}8cm*(jq0fOezRz2FYdTuL@(r?#eW~pJ^aUKn7MY-zd(eze?x1LYS zTajP-d`bkawhnBCWQQ3ETmP+^k+!-8t=U;(vEgCTF^Q=*^WxbtfO+KS?j2|9ZV4YDowtF%9XuJ zi|-)3SsZP>gJ~@}j;`N<-d=GBR;&Wq;ULt-QO_MDW_XQUI?xi8TPd^yBRXh1m3P3f zSHHa#H+JOXe&af^6BMwc6?cqe_eypb!#!0wT5_lpyK>oyt=K7&FJBls!TA+C@vGDv zemDghGy#Hd5@i^``IR{RVc_$PZ?)ohA+BvfC%+2=qup*u0zO2fr44s+jm#^R_TR-~ z)qP)U|K0;j$&?C=)O~bK_S^q&zY6x-Pns@`%P<|?^9w{g>&xJ5U>_=n-e2m%Iv^>H za=Or9C23UNg$9d!k2<>0V0G`2TQ{Zw=L6*5jRp=rKx@0`=Odu@eU4;n$qR)lxP9Lz`+qbVb-??rIFc`)kXiH(8ZkGMC(=Vp zaF}%eKS(eli_S59=m^#P!{X*hD-NmRuoMpb_P}EB$49ib2b~{;(=t8i9FJpE(}Qyb znK>+$A*w73T>NpX^&JI;mBsTBRqI z3dN_%!9>JLAfNnAMC>PiN}Jj3afUMBHck4hmEKv3 z{f}A`(L$Z}Su1QU@_N8bKw`rS@Mef|hBiPDwSwzeS|x~6d0mtth?CWs=g}9`IubjC zweMqL+=NI%b}`wSB8%E$nq?|Fs6)PN#iB=Ui`PxXQR=3zT6q!4hqa4LMHrq+sLfRL z7ks}bZ!-~RqAFXlM={C<%JxAsae_MdM?43kSRCujP>B2=smBb32)IU5)uM|!^I9tm zN^+s&)S}kh>ZevI#ga0f!0ItyEe5JxZ$dLu&PD0WMQn=PB5!lFh2L+q)*J;@)zMya z(M_FM*NWYqWk*CU{c0|b7NY+mVF1E8Hj~=`(Lu;;riJWIZK16L#L1>QeJh_>cyO<4j{)TWP!nyv*8KX}*Ox!!-48G_-{{!n6b*A6tlH)OH=MQ0lQ* zo=gu66i28d;KpS_z7+WMK=CQHb!V$IotAZg$4(6tvG~UGB~SGp|FRUP33?UHvPALg zO=zv97$rnl(RE7{uWSgJKY(_LAKE6pqg=;W@PIf{s1Rx61L8s%o+6ZH0b|8Aje#=+w9I@(B)9^UlCKR^kZ3*OpFNiA&T;quZdQ%2x`;J}6F8>&Lc% z`#!NkxNQ%LGlV*KDtZw4R!wSC?)u>T&mhrW?ej<*7Dw_+NzU0+obu5(!Ba15lZtk+Vzl#Gf>kg=OJ`Q-83qH z2%{i!dK=Cg$pUS#wK!IY@S*9}qSF}nnQeV1l6x-=_{yur2#js7KQQ&c|Aey0%3}rh z18Z@vkpBcVBeLM-OVbCVX6}PU3n5K*zy|J1p@Y#A)lYFrwS5 z8H^tA^e2}gC}Dy>%^QLe8vWaF!34v^mR@uLTOS)DK45B`(?;+7rg_*QxdB2mpzZ%t zcUcH$!_P5*nuj3OqyVxV%JmPR=}hYbXbDs2xwK^{_xoHr3b)#7UK^_{Y+R`sD&lzH ze6qK}_;L=UwKiguCU{|6zfoAu<4>r(3#r)#eOLcXn>0ab%P9|w&j{Ji(XNLvM$JN~ z=wWfT5E4S>8jQWl5W)pPsG%>=77c0`wv>4TV^*X>jp!~^hEcNyWhz)kwj%rkm$yN% z$QNaoir}5nm2J`p`*fxe>u3qnv~{$F zY3VvTU@JPAx<|Fq<8`<$$qka;%4ZhnmMs!!kD@`tK@IC^`fv=M_GsG8?%)k{j%m{- zx;-2j#>CJdJ0zGNLvD6(C%;6C?cndenReKr;1!$c6mX5j%WeIuL{>Yp|At=kGBv}` zv^utpe(1nP<&+WPBSP>iv~~nivfe^_N1$qUuhKCnZP7FX#+mnUoAZ^6RexjCe6FgU$;fse`8%B z8U8--?^f*htvc}$brak{ikN$H6v}CpNvlSoT=AK-m#N1gDjJ2B3_3(LqfoERLtt0F zus4*n4x(0_`C%LGb;x@q3mn8bg2xfca6q|XtE_QA{OlaE9F5kDKi)>?U&m>Bt1c|x zj?==?XpFMsw0X2>Z|<7gCY75jM`2Ho7RLw$r|9}<41l=PZIZ8|KifM(2&KXOCR_4s z=~+h%_4?Da#Sx{`=FTkxme9YK{TJTU}_AR^BIER*XRtJC;xe zdxn&@VLNHTN=W+O$B2&#;g`tX30;y~*2b5&`Bd{hCvmvB_4jSkC%rRSg_GzgB>zMm zPUuUUYO){8b*`gOrge>!F&3pa{Mm-%#LLE_w112hrWf?5=q&?OgiN~%E3 zE~tg0DY=bD55}6(lJO9;wWfHjNV%+fY&_;;M>8r1&c_DLUB!(;teUpCqSj?H;;cA(8}qKkRvoWG@Fb?;`78+zPs0o`_kX!Kn~ zZWCF3S^c-9q0220g~=14Z3M5OoQX&{YYmk%&3uvCCZcu`>+nvKq9Z@;E{;?mj`|zN zS`Rg0I!vM zYk?=E6vei9is&Om4JnjzM_6cCD04zxiQOMTz zhp6UJ^g+;IJaB;g%Le0-A7yF{^@P7_DDCwG^VAKcB2TDbj>E`p8gsBMEt!V!dRx4& z#Hub-*=elG+Toca#r@kfai)+yf}Ex!9hkwEOvfx?F_LyMjU7qnrh_@7!HmV#XLh3L z{GEdE05NIaj_6No1DDCmN9cE)SCx&IAwSPFI-C<-Uwf^ zj_e;7XRBS;x5G3k?_cVk63r<7ame;qfK`fMJo`ARQ@;TZ2B1XI8}UGn!Z5nOpsLOH z;eq!OZHA}dyO}b4Py&lMx&-%_immO6*%k{#)ZKTdfGr-Fx_nUgGSLLT5YdkFTkN`99#vk(AVsiz5q ztcWap@Z67bx%ci97+LX8(qvx@d8^rXaQo!m?T`<;#_KG_EWw{o^P z(%fs+9qEDtmG6OoIW$`wt3H=>N7|w2`+v+v#>V73I0@9(V|K#Mx5@h{tQRKizJs%9 zm~^!C_EX|$b@{$KSg-YkGo!MnAk9YYr`rfDc)mxre&F0|NA5_+tyr4a(JDX8$N{JB zNUsd1<~TG;mLG&d^7nV7cfF}*5z2GZ4-&in0kV7=6-<7Rraq14#dY`4r!i|*hj!pL zh}=rD9)I;|uxG*w8sv|_ek*A@(~#A)${*}#6+uV+5jj7C%GqreO@rn@YKP&4p&yh* z>iRk2D0BVx4(U59Dt{898gQ(mcLg!VL=|?dVvbSs zJg|h_@eZsYX7_-Na1kV0?|>O{9Om++#zqU#P$W^V=k4K zJN|WvE*ZZkQF|Z8*1Ak!O_%BR0?|#Aex;*dOJ)tE4t{A@$Ymj>6|2gQdsj~>dZB1$ zYS#xPFBB~tTq{u+L}G^W8H|$R zAIaev(ZSXTd=w`F`)dg7uUrbPi;2qS8r~24Gvn69cr zTF3G5$F^?OcoS6|uolJO5gLTBj@M~-5LlckT?a(#m(QS= z65uan)ltS`aki%E_PthR*2te=qN=}5U5mjQx(1Ge9Y?4;&tfJG`?CWxo%~=&?6a6@ zvzt1kL&_^TpFImbSldk3pM?>js<{IXL&|S-j0;A*0)2<{8C}NWkHUjRJ9D454r#lk zGR_YNL+yz*cHpMo0yhlv&S02K5}7jXdSGYY<1?3+u%b4Q%%2xsrse^k$UT5*07k+@Q*Ul`=>VcH_JX&09Njc9$#DrOO!l(w*gocKPh!X_u zgXA9qX%_P!-U&dZj1P9=(58GA>W2_<7-fWF$?a!L*F(|ro_3wE z>*6TyaB^NMdJ4Lcw0tSI(@5IA6!C*b(#fTw#x`>=K6;FOnEN!ZZDq$qmEM*C( zBl|FMy4p|IDLtyJt6mAiy3B7B9SFmUHE$GfZb$raJEc5oqN*N6*TNvQjqp2UrVJ zb>iV3JdkBatt-HeDc&d`4-MS6!aFjUX*+R9ZKfF(NUOs!_xnCYyTehg{HO330BAe5 zZ^F?i;r=veC1_;;&08rh99A)}vtJ;wk{In}qACNnP&t58u@b}305=q7J{f7Y3T5_% z-DMSqYjj{IhJ<{zW9=#oPb1toM8eONWUxDX0hmRp!xgxNgdl20Ji&S~IjqLej9uIb z>yiAf+M3mn+F`+Tcr_;Qvfxf>Jncz=!e6tR#lrKQSaQnG#7vC9d|eyTDGgChkZp)S zTNE$t#OA-eagY}w>P+32b>0)C19I`JT0TJJ3+QEVKu;L52K;0bPTow@!fEXqG*Lk~ z?P6LLPC0A9pW!R1d=2>4brqSfg>I@^O$*l|d;&~3plWSIC*IeRi~sFf@ReZ=HNtq! zXD)}l2>y?Kk(RuObSht@tuJDH2Sw7!7m?1`7m%MeI{i{>f z;jN#**aFsf#)l=FBd`LTwTwjb1x9sBvzV1MbUacVCPYTjMc@<6)_3+xYEGvRal(KN z#W(-)^0fk3B(QIkX7gAl>V_Gk@8uPNFpj<^Dg&^kyvKrDIqR^NYTDE(eX0n#zt@R# z)jltGVg``Umn_31DYU;#TcaRXnznV~Haunkyb%_Ku65i&ZtKOhYC}RNUjC9_cR9Nr zUFVtD$v3_DX}!Da#T7zK5`{*i%iZ7Xlx9#XKi`xa4Hop;)rsesWOpsQgWu|8HJ{(D z8nOYb6|2O1I;Azri$y-0M6D*`;Jr3v znd0nkq6$AqQJc{3so3+`gfkjAO>dj1*FNyA^s_agh{}fVP{}SxImDyDE5*D$3 zxt%z=w{4D>7UT%&EPuSDLT9vT$FaI6WX+F4rthn+?!63`O6{>LY(fDyitQb z>zFQ5v5x5gSMs)O@m!MJu)ElXomQsO(Iqv{jjTK8}U4-ll-cV?`&Ikk30MHPYul z=I)aDCOG$Suhlv4DqumMll?2mJNt9;e+A|AD5R)Y#HqHC#hudA9NBk}y8yd6b9!u` zi7Km@ie6z3{i+iOU}O$`dJB3d`|D2J6}-6>oVH^NgjdtIbY=_E3ofJUTUfvNzEe?) zhwjs3wP*LLXs4+M=Er&9&jm8?NR16(P0s(ePiFvvue(m=vi#A|OL zx2+IaF@I9%RxGWIf6Q`O>ho{R8k{zg_1h@~B$~b= z>m@v^SS^MOhX0SsP+Gf1t3Bz1gGr{t_$E#4LnjV)TB!|~{eBvS+4IFhG<`grJ9&T6vUj&YQ%Hb9G% z4;(Mrjz-M2FyNUQ`6fi(tD>6T+b&L2Ck-?xZ-m0YxLur~E*oUP9+14b{NxTqsvc~R zER@0c`VK5?Qf;Vc2U^NtLybFlg#khII@lupVVcU+LPJYlhkvey5}Eplbc*o+EnQ<; zrKPUd5ibu1l@dUcY{@@CbQu;h-0-j4_`c7Zs3L&bE8Bco38LMEKs!Uf62?Oy1z`e! z^~ zdczyyaCH;hIf^PgCJ_@|hy%?|1b0}Crp<|%AS*}H$wUZW$FbC$C{7+0IM&dA?J)>t z(Z67#3IX;H$&W;04^Trd?nKYwCfx3w=(#v&12#@uEww|bY^P|UNr(FtMC3mn&sm`+ zDvNQ{xD&mZKHh*6wlgas_1u#%6U0t1z?87z2e`xG7TPD$)+CHG-4p|c1UAoxQdJV9 zW$?e9$=q9u<%;ohC1J^; zvrrmLyOPDJrq)Xg_h~)pDcV#ceP^YmsN(+7wYc!D7?BGICp#u0|Pwae4WV2SGJ3Yhd9l zp|BR+gZ!Oig5W=hL;Xp>5<8v1SLg zUIWVlu;Gl!A|00kdRKz3@YBPuZ%$^d&!;!MplBaQ_JUUnv75FRHkayc2Ki+LGVaBB z3F9^v5jaIQlv%WW?ViY^U3QO3MG4%KaC00Yus(^_redJ@zDc{`R)_2|U>`x={=S?F z^ILj~0UIvzMZiJ(&>InZ$Ymb}O!XcEc12`+-%I(X(PhMj=mxeY`ebMip z^d7s54bYR3iyduXw@--yT7!~nG)8S{uk(=ynYYRqDlCY5;P@Hb*gZSEw(7$f5dzL!vcLR*bXmwjUe-P8K`=9-832swWtAR#l zh*K*o}{;01Ht75R{W<~ZH=sQPi3eDj4_+UDffj%@2rfW=-hENw%o1tX? z0hl9c=v{2M$jq_k12jXtco&Z@$s*uOc9+`r`wz>6yV$4!Vv{xO)$)rILo^VnGM*90nJ3`aX<%=r}oeDco?0`f;u0(@hit!oM`0)*c1!xSe)0jo(hE zK-Fd2?@G%Q_PKKu9brto3nfWzw<#aN-L$LU{Sw?lH6DQc2=&R{3e(}c{JmHRAO#EF zhI${QjBH?qAJDvG2xk!w>`l*XpcfVnS)sp7gWkY zhgBBd?SD#?MOh)j)B1!_JHJ*cAOt`x7}Ubzsr+HdYk`HCtLlPhY6Wqo^B;^hJVah@TsW8hx8E1gn= z*O$3ym-sSnH}J>s{U@+5msW8XXUj2q?C7}@U?0^_ck!~U{Lu8N6KL+-YU(-x`%-=a zG@4)e8?5vz*`EZ>l&L+1orD;wmObswecv!qdDhS_4v<T z2s^9o#|ThzgS?rlYL$TTAG2VqRRV@5!sJ{_IUE4jD9V|--{gR{WR)jc42!&ZS9(US zw6c1sLxcig7nGedpFGxl{-CHluwD3{bdqUMGd1Udz0z99_7m8$tMzwj=_zrHxoZ;C zf>s`j4i9h}2E$#_dY3-A+MII6YY+LShbAR|Bh{Lr9uteun%q zAL&BN%hrPJ>~^2p1v!4`Eado?><*jW1rC#cRKV~VW@?>R7xY}YeC`F{NbTeIyWJn; zPKbL4%`mHrU!UVQjc*npo#@$J5Om6{d={J=?8ous&BT|_!k`!)NEv6*rg(s^hNOOWENdXO_MP65Wh`U^Cfb6gj8k7Si|))!DL zd|#u`FHkk#?UeC_=wKSZy^Gcpq)hD>nBoezb0^AKsEg2WkvqF^3_x~23Af<-HmyRI zLhReLi)r24bh3yW3{Tz`p`n8JknMTUvQ(PQ)Q70?JT_B<_G6e49XJnZ?Vd&#m}aN3 zAFe^Yr-W%on6&q3dNDBT0}AF#CaR5uMkduh;lewI55A%{EfT7hm~;o zzzm0}i?P5D70m1)^8JwfOMqEtF-6+}i_M|~j1|k&!8{9?#SvUh<+w-K&%wMMSlSVq z{xz`LUd%Tg^*u_v7>hni*S|)%RA8m@H`@Lqa=8es4p^G}jeN5e%;SBueKu{mh`6d_ z3YGvY7HB4rR?C<}*s4=fUj6A<4w=yp8 z#s0Wk$`H5uoBp_YWr!R6ZGWD1a0@|~sE6Yfe|LYHwnAYU<8A|kvcM(fUAQzVzo?)8 zJ>um5K;_>fPT1uxURLt9WMGA8L+<5h*lK|IMHLw==M1lO@ofcuBYsCYgbZ$KW|VV= z*Se%H85gOE!-f3Zg$McMQ&zek;EwpEODg0_iWCI5&|XbZKX9fuScvhD+U$Q4=UfVZ z5Pj9Ux-M9;K&3-|zrSEwbrsxL?{WhsR3I(P;u#f4tD>PxGF3XW3Aj4<&n_I} zkSnUY47cB3T~ee{rXaWl{PaN7WyEuD>%v7wxvYg8uDYGeD!cXUj_B;dogFzH$19@N zw8YRwk6(ca&$_Ei8mctLt}EQL-Cg{;4=*nZ5m0USPZy3-%8k{`{(cfq53=mnU4_51 zNjF|*lsPB}ZlThIqOPJqDzk1ZQ#V{i1@%|a6BSp{6L#kJgIcwxMYr^}VnK4OMC4RU z@~-5_4|ZeCD_fS5f#bAYH&)}^!W4Z8rrqL7-rTgI8Uz-iHB8;e=SSp_uI=U{b;pry z*pG;5G5mhFjd?^a7!&WA{fJyrMs{Q8LLN9qgcWi}anaq(%}!vLk5;}t@r@0~t=G7X zox8EQC5JD&hO~2Cx+QnHiu->;d9qx|{wLn3b?e3}IC8M)pAgJ*Qn&PqQkg7-Q^!Bj zjWH(sSHs^lZc4YZ+_$QNh)Bojswx-(3j5Fipz7)=-Prtr(mQ2DQr;z_`=|1{&IK?2Z6(X!P&&tLoH&+=@x3|zh8)Y{dvp8^Ic9IC1HXYg z<9ARaLYiltgO2e!e?vb>Aj{jp+JWKM$EMc-(gNQq3dcTx`H@kvV9{Lj%7 zZ&DXy?z_n0cZ6x$MYEX}yhUq&2cD9wgpDbL&h$1eAp`T-&3@1&fob1if9O{4aGrSl z>^3(|3N5)U+D>-e)2&$TPApP|t02P656>_VPEbcjI>^{y=`|d%OS7->I-Ff@u(bF3d&v@NfTi#Yg5SOLurX5&FdpFlO3(;@{r{057e-r*9!;ar2K0!{0ovMtp2bq?Km*v( z<{%Zptw}rBEmd-1@W%zrMx5|;YUZ%c?~`RC;ugG5E{zzN#`n9GUnWrszPL{a+I{MPmu8X+Q@rRi`%mV&!?fy8)U687qqDmzi*lG6j?g8U9;HU6+HA6H z5^Y^vvwOK4`LMukzkuNjY!2s(KW-0;ufR3gG!Nm0(rjAG)R;|)O-Ls)hmJBW%%O{* z)2)toOYd<+rG2QcK7~jl1%9*d`SFc5IsGd5mEZ~UzmRVIahm=Y%5QdpLjU56dsn)7 zdz?>kT=@$dl0H{SXohGgy~-1`o4NLD*zJF$&}K~5fj@CrdF13YVHf|tee(0 zW0I`8j{Z@Me>N?w+*HfT4DTxjv|!RKtdY|k7<3U6Vr@6Esikvgd^(@+-m0-^{kr6=UU42C`EchH?EIu z$1h;*Z-q0du^TrKWN#0+c|U$$D_7>PZk#@oXZUmuSKZu=#|GremA4|}2tD$`S+f0Y zT(edTC#7Z{aGRR7chmefXyN*fZvOE&)@#x^pw(RnELzY8cLfKuFv`UrW$K6z6n&K1 z$H*FuoR9zCXvBbjy0Jke{}fI9-$z8{qQ%k3RD@9w5)Pz+YvC( z#0WViw_pI=rXhlnmNttM1_phH6~CzwJD^JQ!c&M*SxuA-+&zO@lg+uFp^- zT3J3-v7`g(x@wHrZwj#L0F$eAPAYO>+yFDIvn*n0TY;kRH6C`jr!nrGmVGmh4>yVQktF)bKRIgA^} z(?xd2xzcT>0TamlE>Ff2$OY6p)y>%dQYBZwt^)G`uyMWlG3E}e8kqcA0o+_EUtks! zY1duk5ipUC-bLE!6X_zSt#zkHxHa|e_tMrOP8H(VOd|U((P4sqlCl2?0q0?T*+gXo z=74YhbH_hNVA{z>EPG^@*wKZ&f*zraE_7+ilz#qd>H=$|Pc>p;D6@vH8}0&6BN%zX zF&OohbfZl9-n6w_oMoQ!gi-p?lFFZj0sj^}%#Cx6QdRFUUne6%rUjF~QQT!-xZWt0 ziAu;0qqs^i+exASU`NXOO{V^2{0Dl8-CJbd1G{ADTSjRfFJSRYV?EfKD1MuE02jP= z)6pJCtdiYS-h(!(#I{NgjDpT7WGmqqXhDh*$5P~z)N3Wt-?VA3k)QQ`n93xiZrn@P zB*e0Ncb~1+-n{Y}#4~?ltKi*z-da2<@UBrY<@1>w`4mgqb#V-wrMA zeW&g_sl_W0sr$;|a^APE3$EaOWNQMNw2!7UE!am(OyHfqpAy;Kw4aWeAS*w-v&Xnq z8sTRXZOK~D;^$~(2M#@?k+-15s~%~%UyneU@6lcXk+3&=hN<5Hy3RE90QE4fJwOho zTKtaeK_05|Rf`Z)t&I?PkT#kko$P~jfNAFYbOBUdpJ9YWL*B6;V5Y^f*DP`~)8a=n zkKrb~*1_@9`d=xy-9J zQQ=23Iyj8Y39>gwT*nifKCbVc;50Q9XO2q4k;tIUNjizlh3J!X1#Y$TCq`+baz|Jk zpdF=-$T#91`T`f|_0PgBIDg6ov^5W^f%5k$9T=d+DUVN$%B>7rT);;d&$HAuKs!~4 zKTAaqAj6b#8nYLyZeZR#Yg9B>C{xd{wugthzkx2m`i(36^WeV>-}14nL;*irA_OuI z@Tdxazv`UvUmI&-z^s5ZDSHZq7FuVa@N>Ftp>-3yz97v&E$*6}r^N$NQQz~lb)Z%= zEabfLUx$yvYr%-X< zU(p3ia7x`*)NHBM4Dv!bOK-v+Qi5={eAmdKUhXKG545<2C1#BgriTTu z;+{tE16tj%0ASX)AjY}o_~TPVVZiKY&jZ@A>SXq&FCNh12X^pjL%%Xwg-<^kXoXL+ z-!RM56f5m$Tta|+rWdTVmIz(s4{AQj`=6Vw123#uK_Bc*{>!CeUI33n-I z0I0#CL5c(Q9Ni$LfNEV3-X8Hly+9+zH%QT-Nz)pnEKmbz8RL&3eb8X92FY<`&o(K- z8wrj?Mxc?P2GDqRKi(kaffj(4fM!3@Aerfa`!+}(pcYRyNWq}Nph=)rpn0I$*$q+! zXaT4ZG|dm;N1>qekUnVD{01o()bE)FNk3{E5?3_%Mr8YGn?()*x6at75NYmkCK{Xk)vkg)msKwW4 z`mqQH>H`{a5ls(T3YrRBNa6GGMacC5(0Gu zb-sdvfM$ahv-@g;R1ca~iHux8e?*glMpS`EnEu)zS&c^vfqH=Y)ig*Ups}EFph-6x zq-@YM&_dAc8x7l}3VhT9(1U7g8zgI2)D+Ya)DP4X)VU4?0Zjr;2dxJ!1U3AQ0)ZCX zM!X5g_zz?R8ry&xgL*bKNUm-CVr#DIgprxQ; zpq`I4O7Wn6bC5A;FlY&AT0ox>qp?; zhysGff<}NAyo7L|&asVB6}xveN){d{*nvjL6SV#~!hsqJ8l^N)&$Flys9zx}JOu?T zYLwhTw`E^Ijqzc)h?;=bf72)#K&yUel$@s`!OM+OAgFUCG6XI73E>$388!HSb=?nq z9aA3o{o6LnAPC#UAlj&4khMW^X%G}cqtZ4QRRqCBkWviF4NY}a5Jc~wRuEhiv9fv* zD+oIXitZYe4Z4ix|DPt4Kl=TBPMbczKCjpF#&NlHXe{#FDqOnK2=mlJ- zbH0G*KecDO)RJLMX%}C)F9nXHp=s?>gyDhhQjPk-?B|YNUb_V9{9oE7`*^1I&~_deHTwT;mnL+7ZkG;phMD5iSTtCS#%Q}#VGJ8Eh3n9h zcA0L{;G_;I$AHb(SE99DhqS8v?K>n?Y8?_iopv%h#71kkc!xBSuy^Ya4|O(GkDWoq zQ#&My&c5tDj^=?KV$9;gLudf4Lpvme=3hIc1GS?%WM&c9oywl!sGZg!4jM%rGJr`m z&g6QWiCt)+7C(~;Nkr$-V>HgA$LjdP4jEI&m#_o&Y(^C8kP0-f?2sA^ucE`~lv57< zXFDYCEN0>bD#q|d_7X>ZRfn{wV>T}zL${f7#T;W1#*^Q6$YK&Yn|vpg?CZS-wI4eq zeGax!5G|}gAM4R%zi$s+3{*a*&85RXGg5T02z^|P)-N5>fadxRS%=2|IwW_V`u$I$ za2`F!5;TA1-l$_-iTZCH(u^(!XapUSUBZl@iK*W^q!RTFbPT=r4#_y1^X&a?qQM5+ zm8kE|rpwAdcS__OI)u6B#JPZkNrp3-ot`n3*~y;?SY%o3ppEt(osw}b$NO|jp>kTM zRG^Qw%3OBvR{4jpd9sCn?Ub1qPNzQ93Oc1;c|xbG!{EeD$vKZ(d`hPj$4U67(?fL5 zWb14U=XA;d+7>;WPyTtGQi`ehol=M4f=+2u`4@Cb_W5{Wr&#D;)G00+*U}-3Ue_sO zO1AQ@T)_1<^`n0W*P|Ejlz7esOvzoHQjHF-!W6cmk8P+eVahIKWSD~<7Gj7cXjCy$ zbg&lnyD5JWg}f;A+f4|1>3#1L)NFQEdA zVhW2ez;ZMm=AL2{Q)pr@^xF&fV?GPJQp^yo?|dXvS0NvuQtEhw8Qx2_BI<%0Hv+;T*`dE)nW*2{6yk0$jIOwp-^fU3FcLIRU@LiyVJrIBgIZyiq}@b?n2QcZ(MJoT zCo)1bPU@06b&QP|!?hUT80sf?N%qaug9YfF9Pg4+649A-0FzjU+9`AZ9qhr_X-Ol;TyCfgu(HI3u_*jq0Yp4jd3L3rxZ{!|ga7&jop~Z~pJT$_Jhq{a0~nxoC*?64 zwYwP+>Npb(v@nY0XksN=Sc?ue-l=-DjEc$794fqv3-6&rXkiJ4ScCTRE@?*nUSXsuv`Rdn=GI)JIinL$jhj6TEX0NPlG9=4!W&qy80VHC}0S)}M;H5$*cX3)g|15Ce%^3T(8G+$89KZ(=} z^h{;E$n%Q!OH47kn6aFmuj-N_jG>L@%RGi?VXMl=Hgs?RQZ7)9+B>Omb# z(RwA$$VkMRh&dV2@hwYj}~fwXQXIgHAY`&q!`0CbTRFIDr#gAp^Fw;|KJv(k1ZIYkIowm z1dY`^Ef3Hz7GqpbF#{xQOre9V=wS~UZ*oBmzQssUf1AaG0S=(mLbw3_Q#UoQWY?nEHs3ppT8{dEC=l8u*ySgZ3vp z*XVpoIgGV3#pr%PhaTa2EI=QNF~Bkm(MD|zGy4e7e~d%}88)_{gFd?0p$dMj8<3iK}rhFw+|2vNlY8&VXx>$`)2UCt#7b8Wzn~preZb!w(&3HVDvS-WIO~`( zEJQ101~7?L=wm%cIcLTGsuD?$j+w<<8x*7Gt|m?{n0H z#mZf~r3T}E20bUC?bau_W|J*GNs7+?GY>Z)El3Rclx|vjr z9wt%CVt^_idoaYwFHr9uY&`w~&%duTLY1*kx3pl0=`V8Oly1pE3m2e+6&Rq4=G1O! zLLYn3$f4qwxE_np-H#5SmCKBwaX`0(7(0*|TSYwwbL&>|{A-6WwPYmom;v+-r2{Xs zn)B%)8i#fB3xVH@#bCVu+>aA4x~iK8g-tfRR_pKZcn? zZ3ee0PQoRz3he?qfW~o*q=5>t5JN0M=XhocqbG1rF@=%WsOZFQF)%rkj$-r_Zh<<+ zM$}L3mN9fN@9)%$r5HV}TjDh&d=ialnsh*&ID<9tIt`$K`Ybwt0amH}B4z?ZT#M$J zbfl36Fc0O8igb|Gu#O*)3tQNM@|p@R+R<2sC$GV-@*_+p+eOvXvr zBz&w!;}TXi+PEI|OIZtVZ<3KRZUI`CQ67`H5(8|)fy=vP0F5i?a1$NFMQF!({4jbY z1A2$^S25EVy_)tgZkIDvB(!U~`JGLLSnyAduj5vreN(s8qiM71F?tJ+k;+H?U2YZT zp@)U2-AV)KU?m2)3X_ZZfJ6QEZpmooR@}j2ZRYtmxCNDD=#?x!jA4k;ySP{HQ8AXG zxujca(Zwc}k3L41GNtb`gP4cL-F(8Ki;FPCm1sNM0`xKR0oUEbTKXVP&+g>{GQ4U& z5b(VFxMvvRdem#Uw=J9G6U;~FLDm3T5AlJ89){@GGW8#F9ZpAm1s%sA!Bk_);?S9tylTIuPle6XO^K!upXHcY<8>i>*_ zI1{bEvnbKW7BpXHMljmQjC@W#Sb%1Va%jED=K+S;rhJPv^#$kOW|5-R#Nw+V5x&Fo zjQ)GvOI6?l3a+68ScXOmGl9;B+!72v=GX6+l>3B{qS4BlK<{%t^U?l-r%L6o;Z~@8 z%=n61_+_``VhW4Ui?3yhNNE3Nb*loHL<>Dk{)dLXronGmRA~D29JOz02)!R@Ncjto z7h3CSXf5Ub$K!}eEJycOZUF|^f<{1jjC&*||CTS#}j(Q#1JdcpV%WFMkn=12ikvPf7$OTzg>^4L}&XR@ln%yWK88_?m9Yz1!(NR z{nBB%*yFsDai=H(Ph196 z#-Z#1`U@4|Obl@WI)CkvD)jSvWEDmaqXER@jU#&` z<9`h3s2(ZC0Apydv$}&?G)|95=*Msm)rn(S1HV#mMvs)BS-?KIXdOofP(PlL{YE*Q zj8Qbu!~(Ri7+tJDZ(fhoVTdVAm2m4Yb~gI}2h2d6L>`F{i%=`$o}+_}7~ncgUPgnz zQx2nOUd{}ma|I(oH`XIf>iBBv+dxOk87YQXkI8Fj7=wje-%bZ^pdE~xi@5hB^qUz$ z2NmHW^lzmD7`?Mc2GF{TndxLIaXPw7Sk2GG-KQ zhc$yfCcD({|9e=~WCYlQ?sE1@@8%c_FnTWyp@WqwACoG-x<^`7K6apw89m&Z`{*Fr zXrYITF~C}M9^|o8K0-Ua@l7&s1r7C55G!!?qjU(Z$Cw$kALo1@4L-q?q46ZE7tJ~r zVLv{_8o}tZT!$g{sQl-d>H$pBaZF)S`63;_=u6ZeR~f5VL>uWLn)v$5G=$+RJ<@{F z*C>eoKX~j0>A-3lL8N$ku(Fdyi>XeY|5YTMZtfxam_9~DeO!PcI;aiMFq(tR&>vK|iIHPU=olt< z?3L&y8r-c{%23~(U4<~2)hlZ-wMVby3iax}QiA%Py|NN7+cQo9b%Om9(<36`e!aXN zLnLLe(;aH;T$epT#5kf?O!TJrN+m{*>Xo&q9nJZPBJ+>!l|>kx!G2)q6tGnkdZaM%j|iRma$beo?OssAIN{oBk&e zdv>oZK<}(xaWKjjajVeBwW!bSmC4(Qn3#_?7NN#ga5ly*5-y1(rqqcN_BKQx)3&F= zvza<{&gqrK7@pfJ9=h|Ha*c+u2xAMV5Zy}{IU1KSGdpk|%h0}@DM#lD>c`lXy%O0` zc>b@Zf*omyeco&gu@1e8UI{U{p8TB{!3|V^NnD58A{t1i9L_}hMrI84o46j6=%I0Q zuk@gAGmxDrcMI*Ib1U`k9OncHmki@JWNGlJdlKFVQ~&Ecw1e}FZFv6^04kM4t%+nt$26SaqXr2?JDnL)IkWDTLoer55Z zKU2Z0RD`L9UTH!9H5x?Y@APmoBg1^<>%CHiek0}7@jobs)*IZ4Od7@l)K>RODMsJq zF;u?YD`RLjb3Tjq*kmlGe7`p?H6*O}d!+%BxE75M=plw5Gc$WIRiChkF#0J|jvo4` zw{nXx^)=;mI>zo}i!t?GuhgUQ0}Z3Yree8!QqM1(N9R}CLE|^>UB+IV=;gUYcaQ?; zZQ^lL`G4w@F*LUC<3F3y(Ovqa5~I8JNfUb5hQZ`MNzdkdW}oDvmc^zq=wmI0m_&nZ zyw)n&wkxs^9f@c6iA5rb<)}~TlU10)$P_A`O2f*WJ}JV~zI{@S(P@2@p#khci~YXx zrgDsBXzkx8zB|}yc<3C(`GdLs7|vtz*nVll6b|4As2#$sn$a%>=ohd@3);u^ zOFf3i_e)QlgjU!u*?C-eO21TN^t66Sp^t6ooZc_SUlQD4b$>FSxI!27)Q~lC{_S4jl z*0cS5iIsMr>*x6=5hnX(Et)S<0Y)1b@pLMDyPqK_Go z@{@k4LknBb`;_`nZ)Jv$VkWQvwa@4P+MmVyrG|v@ITfpn*nos+-aH`Dqq*>Qc2~g= z*JJXo0m+Rr}B z7#eIiQj6ZKjnahS;~Qo2aagxe$}xC)qqu0WrAG_K_2)K9+VPygJhWe-AnO0z$hTO@ zZ{8?9m|}+y^8`lzJFU0?Blm+O0zmczJaK3G$G@|j#MoB-B^T9?b zLi6{HQiI$qVdQ8=1|?%A=O+&GWmWFEHprJ%=~%{~v|yMuDA}i|=YNku$v=fD#hIw< zgR%$>bkN&#P#Q7BwJLwFK^Z_BGfrhq?9C<#XlB!ZI>vhRu}S6cGbjNDsGmlCQz(zA zse^oDf`pO71*lIOlnxAY>5z#B(gCGG2hccpP_)yj2=h?S8##qpaW=O@(4PJ#!-XPtd5T!WwrEgN zXx=!;zw0wYm{UTBZW@&7XkiIzx6vMYSbR3u$8To@BuuujNui5A+Dln1=WxM26jUxB zlqz)Y9h3$Pt7%9b*RWR3<@}04zLd&H6U-DwpQPjHVY+%H2QohdSy_G&~0D_F!lDJ^kD2AI=(>S;*uy{K*d;rsb&@r#@=H!V-f=lP`iMN-e)9Awy`P0R0|bj z>_gTD8Xr;aLI&b75VSs~UW|Ui3}Xt{VT^5W(l6rqPm;*Hhznck2>Q4ft%6a;!5yspE z2Qgx_|1u$mu*FwmGQZ}YQKW1IEPIc(8mfi*)OC?<)1esfjXW)BpD0o5Ef#HrRbbL zB-I$bfbyu9(y{Al7z@z8i~*vHH5g(8`d19edW>sV@!I*fhc>X;SDKgyq=n-1?Gt!%>_<jGoXxFlJiOqF5 z9bGgr#Kp=-7`Zyn_7?#r+4jP?B~As8vgmH%o~|5{dJJ%_@(C8%tyKIJw+4Nz#1Lzh zPxDlu`wUZl8|QI4TJ1}6)V}ArM*~|iifw4(0EX+B+B@+_ zuE*4WnKAU+7$63?4z-_#`1^knv0v!fT{O6!4+u1WqeB>Opd(AjZ)Yko)x%oBWG_>% z+{gz`71s|jm1tu*x>$)C`z`pG`hzvKlnzV?`D++vh;0?>Fgb~Lf;W=z$XKHa;Cc+$ zUm^EyMz~!lGckr`7;ev&3TW;SN(-j24ZR&h$yr9jJM-Rd^mnBJOl5@p%{Mc|Rtp_y z@6H?49qQ3TDN)AvbF!Np!Fk1MI<&Ed%oJ<+@`-sX+bsP#VxUiSrnbo=SmgdUiSmFjYhWjLxBe%I8)6 z`S+239_P`!kP)GODI>n0nc)5MHd@!xQH=5a_s9cWcWWqx=v0PMiK(hkno(cM45M}r zGh8Ea{v^XlYsh$z7u%!$2nEo1lmZWO;S-@O#^5O$K8@HEymA?%>BG{5R_3sb zp`SI(mmeM_!TY<5F{Tg8BITaLvJze11gjuc}(ulJD$-$ zXjld?cIdDaJx&J?AC`J_j;2A>3x=g+B^^0wSXQBB4of`k2`ZXBEDO*rp(0GpAC~mL zF}0Y7#`#o;CYEA!!LZa}^1@*W(MSDByqI!mmGKg4b$t1-q|m*R0ibr(ute&Zk@8`_ zu17r!hvVXs2yY(ddwDc?J0p9F5!^8>76!N&%{UEW5?j!y9A-UmjOkBP@twnxk1;I4 z0Bv=A7c+?-HlwkGS65>awP!f4qQX29P8GKR16+jW(qR@FQ+DsLw4(h04b^kuLyQph zS{gv-5vCZ86~nRyJsd;-v0*8Amg}Bm0I1hv-hHU!=z*EVR*hnJGiF zfvLsV>%$U#o`&AwJO*#k5Ss6@c#?GJ1Ev~NA2CAoc)xe#1vQ z5_4W7pO;V1#4tJ{RjPciZj%FP=Q0|P8ZyM&Hmh;{1tY-UCsV~;vMXM|5Xj$dVrBq6Y{1wh%m8Y{eb2j3%$+&iN|wcl^Ff50}s|YD-6?8k2W3g(`p9hzy`}4>QqB2bYh?0<@|b5jyv=n9+EETZ2K( zh~<haO^v(SCS@Z_#nSmYKqMYz2=8iO^-l?^E#c5h+9MZ`?a|{N#wVV(e*d!3Q+( zJQZP>q#{hdKt*W2L_MgzLOm_aU<37F@EY}?)kr-UT}?e7a{etI+Yco!eiQeEjMzVU zkuL`Cvba!te?-zg;=&Ioh^Y@Lhu*)a5R)DiqV_2j{)=*-Q4W(|P!6MCQ6KtisSjh{ zP@l&D*6{&_!H+CbFHX;Y;<;8Czp&U;fnRz4Kjy-KMT18Bh%7>p0Qi3`!`dx$;*2YP=BpT71G%5jVyxcdZ zl@VxMfaZ?8#24*!-iU_oE~7GlVaBK!pV8p%ybKMalSicn-K|;7@a!Gx8mqP&M1HXL&D#W_wRl|g$K|O#t!18wdfo&Dm`c%Ix4wqxFCO2EOZYa zm1;DOpyQarb!bi>m9#IZ5A!f~Bm+R>C|>S~0oG&k=uv4^=cA+i`JaS-EHA42iW4(N zC5FLqqp}jULPmlXu2<(VMDs-6A@?=qFdyBMcpWmDylppz>aDv~Xw4jzIt;K0W2aCb zhPYmxKQ&H;Bz#`SJ9#Y`r%@sLSfq|kDn#>iMyx!8Hy0~s@dib8p4aq->iEo2{wAEM zoz1%}Q9Fy7LLY6kin-V77#q-=!}ZGeTq+=8&Z7hWAp`T#ETIGH7-N_^n+_y_uRX1<~P{84_lGvf0{r9!!2R9xi+tQ~d!LPn0Mi&z^z&wr|v21%qYrpL-l zcuy?4mvXPrDH|0}c^PX#$%}dQZ}EyzDOASjpz=x;n7_DHjp^Y`DEuRYY*OCDsz>K$ZUIJZ>iL0s zFp8;LxP|E6$_$}-8&4M|u^zR>+>*FDL1G;`7-IBxM)o5e!0Bk-L5I-6a@1I~4hC3{ zsXLh=^zP#GL**~w-u{=zZYiG+Xx`1tptFpQU<#`+#JH;pIK1)@UGy-(^=L0=s@pim zT(s`xg9Jk?MYEczMh9K=?qg;!`8osm2^%Sg)<5Vl+N(K_=9{bu<=dli$^DrTzr*4~ z`(5rCI`1(eOn$(OsN)a0$G~+tv7QcpMn_Tmf;EN48U~2b zuekRZe$CVNKg$1`DKtq~-%wCxd`m&}*HI9S|5ET*&i_m~bg>+LtU-M}9YybdbX1-H zm5%;KJ-^XW3lolgGqH8>`XG9FtY*Jn|YBN%2C-0KGlN_+A&~^)bms4`*U(&oL=ObFVS}KQY{! z>(N2pJt8Sw+aYlYNd#nA+4QWF3NROA`_Lh@ri@7pU0kf3I>r|bsQ`I(0Dt#OhtS%0 zOvcdLZ%p#L81epe04-iU>7x6WF@GOLcOTn%`NKZ7UFcY zu>^gz`R~sXUB(Ol(8Xp9u?>^Xn4}L-5cANvXG|=0j5Zp}85!D`Qs;Rg<9ZA+Z6o>B zV|=fWj@(Cs=%J0q{j{f!G2TMLeSpP*8gFKtJV-?t#Sr-~ZxVZOOe)dGdNdvylQo#c z5WQNabclhh;Fh8PIBN!tr|1wSF+Jo~VIFEvGgIh1JrsOz9XErC8mVdXqN+qW3n75RE1l7g{)gG1UHG#8`mN zJCw&H)}oJ%XqCLj)NNwq?=vN6V>yP@whFbM=l~j+CUo!@Mu_EDjIHaL8MJ<7v0>?N zbUg9YEt&hRUUR-)zC)t$GCl30$mGmO4srV4nUOg}B~eGT5rx@E1Vm&X$`J-pNT{Ej z$c~Z8hn7t!<+yGNWr@gC(nKUDGh*gsK78kfeG<)=>Dqp!WRybM{?vY<3GGWpWXh<90L#Ex;z)toP< z(Q7i;*Cys)u1}fOOnMTX*9e=~iHKZBhbt&gRBj*He7@~&J(9Cb zkCYO1MB&2B2)lVja&DyTP4waBErV;jTsO8WwHeIf#4cCp$8KM@M5Qwm3uBpoPF!+@ ze!zB>OE;grpR-dd@7{b?HTwVhIrs3)$YqDCD))RNrdLk5dd+E!XV0w7g?=F2Kza~& zFf$|i(V3Ao98V*CC=rrA4$mTD#8P5~^0>^%Mk;=p^t(j%URjZu#FwPYu!>0Tm8IrA ze)AETkzdL0CWeW$(=#I(#NNaK#9_oy#0=tOVm2|KxR|(-SV-JNEGCu^%ZNvar->x- zI*}rpiI0fSh_8t6iMG=-Vj6KEaVRl^IE6Tiu!swZGU6(tg0P7@h~>lz;%VX);%(wX;tS$? z;x{7R%Rk15?a$1N>`G)3Qwf9k3o)HImMA1nBZ`UhiA#ub;s)YY;!fgT;z7bC>WCMJ zSBcfcJH&^?7lcpzK>U1WrV-gdqMsNcBC|8uc0DulXJT(+DzU7P&dlEY&>fq{@nJ-i zm_Zy*oJhxbOP$*n(koRk?^ z$??5dkE?llUc^_4#x0G<-y*&BXBM5BplaslWAZ0%PGv;CC9OVX)X(S%+{W=TzmAtt z@1yM_y>)N*?atbAt@>2joAh?-LVgY=%?HxvpJTU_iAO3qG&$H|ywY<>?>L^ma!Vm~ z!Gy(I)13Q>nb`bM$BBo@PaiM;Ea{!c({F4o&xhj&q__TjHJ+bC#`?2(Qq(BZh_0;{ zaAy1B%*Za|741cO*YWiJq%+3T#dKn~@$@0g-0tJ)DCs{_pZdwC{N`D#j6|l8zqK1D zlb@x^$BAn=u?MQ3xm!<=-j00rLT>eQ!Pbf*k%=+VTN_@qHNP+tS-LgNaNPeVJu&ik z(p!HrsB_QpgZIdftKJn7YdP3!{KPEQ%jSKFIsTda?D3H`aq&Lm>45wxUsQz;xC`7Zde_M|2Pcs$%+_63Gpa-mDoV|L}cHr zNIp?YR1-}^ux~sovYLYbCeo+zJC~>+YKTUnpM32cDkq(dk^QnFg+vw6K&&J3$WP17 zikNsQaWip0kx!mQ)DW%27?HDoR^)NcnOH$I#yO}Zks?}2w_)}HTu6My@lV7iBKur^ zr4e%pn{!P>NaP=w6}g(cI8jErnpi`m8+4Q?BUW&(7F&ssP(K+nwye?BD;McIPnz&# z;>DZwCwHsWH@}}-eYU9wsV{`x%K2tKZIXOly4^D z5i*uARPh(qAW@gcZ$&ITl>EQa zDCS^*%_^f>$m)BXr8Y{8i@RV zajsF1lo53YY#*unaMwu92fIerH18TIJR&jWR^HwHkRHisSbgfP`Wa~xE2k$OxL zvfYsrB3Z-%#OjPnec^i4Jm14AY4?w6>m z()Ee%oWxsIyr&+2RQ_#FV&c**9-yqBlQ?7CYcb=K8C#m8CVuwSsA=-VPi7?EP=)Y2 z<>xaJo5r1X_m<;Rl`qUmT%~N7lek~Gdb3%Hj=S~riSNuwTzEfkwcmPh{Cyl`EaOZI zpX|#h{^^_qnR_J8Tc+*ge0QN@wVvJ!#H{CWH!-QggZ zli1~6eUFEiZ`f&K7nM4c#!JRk=MqmiG%_?N@uJEcos;++cb+)+|BilQV&8l8Jtpon zck`)9S#$Z9n}vF2qWB(K*k^9y!h5(dcW&Y?f}-52W{%$l(~s6RpOkv zTY76OC-dU*gCccs+xS5R2a{^Yo7uJEjjewIibNjU+IC76S+(_Oow~Y_o-nN|?j`;H zTs3a)(|C>LD)Z~P>SkmmwjTWLUbc}a&ekG7&rOh?Hu2ZZPD!-gtFsx|+{CXcvuAVW zUOV>erA2B8jt{LSe{gPME?zgd?My{>)|&dZ%v|$b>H}}f&n*7nv-M|U=gkMxChk6-X{*dV#t&AigB%XjeQ8z)2hB@- zejj5vYCKcBpGUHYq-D^B=$CmmI^V;VxV5%3nxt{W2tP8FW8b+e*)x>#@jSjwoRd{w@EMBCVksB z>9e53hld1r7xeh`uzv=kG7j= zeUezdLZ7mI1V)l5lt}1bpN+#4_Mo~&P%_(&yPKE|Cymr6dVM+P29WVs}t;=}sE#PKT0 nXE?isT<+=zPN+}Z4{7!MR!+=G=zmVMy83SF@N4y0|M~v_NUbn- delta 109950 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

    s+F9qkUucK%wc26z zDeW-5PCHEgRy)6T{290HuR}gmDz1rw%pXU>DpvnwbFu#Cku>n~{Vx9Yv99*Zxl$KQ1FH_@2!<1*N#CQ+MV`BHwu#_dw0$v~G1g7>M^(Wn~od^1EWZ}TkFyRk6 zZt`qMmJS&W3z(cT8dk7y=xEr?tjG2y{%GJw7$ECO9W!~9$I>!AZPefYNK`&D8fN`T zgCErqGanlb8<;z0G>qS1CdYb6Bh$^J{u!kXW{!r=sQh>XXNkQ`&GLldKWmT8^i19` zpNSK!469tj;-@|CI66Li)X)Eau_PyrhS@Bh>_MQcp5h_FtbfK#m~I&j!_jfZpViT4 zN5fQBIg5qQjfU2!{PWIdnai1;Ga6R2$_>n%rajg;93B5cUV|Hr_zN0j`imNj@@$Rr zb2Z4+m&`cw^wF>`@{G~2B|7d&z45=we|a<{nLN|8nOSF+m9LD30@JOob(H5imcQ!! z$oyFv_?rg4W&kX6R+OJ-08ySfmd-YS$a6Hn;<*}#obUYSc%D7O^7)<&$?63jBO93= z4W-Dh+dI+m3(cIRi|ma}?*GyP9ZHlgHsZ){cqT3j-*l~*Tj-J4k(byD&vTKPMqcWP z){$)n7p^QbIyOk{a=t+5FKD4I&itAVwUSzSsCU!41^^v zXN~z%RAISCF0#NXs~l$b4olr7&lybL>4StdE@Y}`shMMm<-4p5i%*-tD_o}@)4w)g zW`FBAQ@^t(Ughsc^I?WW@((s2vww2UnESICvG}YN`G@>pU1Qdt(_rKa_6Spdx7niO z>}9FyBYCp{zi6PWzhqA_(Pe^6zUtbu_78X4Kh^)I`#&R*{+EhT!M{~xrKTbiJu1HD z_*V5;U^^>Z!T5lIvb@be|K<3gfwDAYpsWt7$Ha(wtc|L-#l-%r9&`CORg_4_>R}~Q zyVU&wv4+QcjN`vG;4zk-logVD)I)oe_t47KtnXb9p1R~06Y62=>&`!*9_BM~U_C5n zj%!%uCe{zGhw=Z>{vq|y$Rd->$2~7{wnUnqD-%jwz{He#C@{-Trruu8icQ$3`RWzJ>k@Oo%t>H{8U7kPy9nd8RjIJeY7KGY=Y3euiQ+4zPAID?rF z8W7V*)bGlQ*)tb-z&P+FWEMdNpuOJ#1j&x_X$>XT${+nZDjkSiG?w2AEoEz+0V1zf}$kc@{Vw5c+Gm#YSz*E7KYJv7J@}jQP~b+^IKbladT1I@kILIM8`dtahNqWZc|>Y`@KQ~xl4yEv%tjN`it_+Z;~i{-{u%JQch*g zlN$XMpx@oF7nu2hCpWS}e=QUeKdgt%EHXZ%p%s>t$$MQgR_?cFnE1H?u}FUq=8tep zgmtzu_h8+>|CPu*WcM?<+S0S~a6Qb~ZUCIm!XvId%Us3Oqjohj9A;vT4n}muS6-q7P*oYu4lUC&z9~@GyjVvVV3QTzi8x4yrN;I zI6i3jAN4Se?QCJ!W_Jg(uW6VIAN}bCjn}-hqxq7?@n2~g-wfnahEODARM_eMV7I%x1h@GsBQyOBq zmWJ5$&o{)joYoLqKG!*CIG)kzmm6YLG4)LCigvMFtT?md^hJ#ap4=t9tHDnYZNfto zV@+Q%;8yiT`|h!~j(06;j5S@_7;6=skzZ|yd5>4D`D}I1F@|$@OisP2yS2|ZnQX^i zmo|QU_qE@Q(hVJ-ZEM)4?58bWvlDCfD;OIe}i{3h_)Bpe1rH3@czI#a2l~uFA__{J>rqb4>rUa z-q#TOgY?THrQSTzC%u>}#QHrZN9&&NP;a-7HN^H7`-v%Hnm9(BAU-R;AkGk96Bmka zi7Ujl;wEvMD2gA6AB%^@uf%%stk@*F#B1UWu~m$U*vA|4v3GvFA-0#;N9-rwCyo#w z7AbL}I8A(6oF&c`=Zgj6QqeBHCvFl&aj#e<9urTCKZ}>e>tdT272}R+h`m!xJSN`| z+gBnX4inSFM@6$ZQG8CECcY$E#rfi5(I(o(RpM%Kttf~a#m(X_u|nJ@R*PSXr$t5l zRaC`m;*GrjjEZrohS(mWK_tW!@d5E+akQ8zJ}piaXNa@KMWRi7M=TcCiKSw>xLe#O z9udD1e-wWg{}er9RP6qVhFJdH{*w@giKE2-h);^y;uJAQoGx0$xnhC%wzyIh#4X|u z@dI(c__dd*wyyuYLQ^2Wv^ zZgp_y*WDj(@N8!@;5t6%wtR+v5*v4Po_|4l=hp=WwM*2puYW5a_f~3RY`b*yDHDCY zSDo==b$0vYjyln^Xx}5f^S$nej+IBBO2>9Z zJ7zFmX0PV489Q>A^j>2PeO!9)vGk{;Cyu2TxE${uOP_32-ZPe-E4`2QqOX>nZMMf^ z$12}BjISx59M#W@>mAsa(bqS29*{m%dGt8$=78HGw7K6{<`w1n=o&YR0h#^B4qRY)-+Cpn{J7)XNn#IvuH%mO#shb`v*VRw<3YD9eSJbl zS9@dQF8BOzzUd122X^M;ySh)J?;;&tr#DRL=)9tFsWMU;|KE39q)UU?=#7F zO^&6-8}bXe`>cl8GM2>@>0`uaMO8i#pBy_|I?V-QrMN=Ai?KbmC6>$Q_z+iegBTWn zl7CeUi9J5$`%2SZlVb;b$|tCpEqwyBEQ)nvi-_+%IhIlWb&-+wbJ^9J8=TzJ#lJD`|S1c8)#742t34T%$b?FqF z_L&@O6)VIBQ5R|DQzlK0&F593L;Os%C~Fg|L`@_bCdZn^6OPU2Qn4{Fvsz-4s7c2r z>qxYTt@68k+NKmK@g?yMvD~q$Xx!I~#P^haUo4g`iC&RxG*GcvJmT1D)ouatH0nf+Xm{e2sfzDk*&J7eupNOy`G#RZOS zRyOCozCEemCGt%QyZjvb0fT53U823w)o^g0%4yN6(|Mv*Pb^dzq*wUx>j%`@GcdYe&9S2_L;oVm@#wKvA)m@nS`H8_2j*lz!`OKh?@R6IIyY2(GajJv7P=fnYzcHY!DZI|6<9qrrnl^sXk z()hXEPL$4#r9Us-K9)XsN1c~$X*~74&r825{v)EV9~~PxE_R>q%uoGizXKkWkG9>z zj6Mk0F#1j!{pirH-}iNNF7tkkHOF;4zRZ*A`BLPQ$90Umb%%#Wt~;*dq%kk##Mh75 z(Vdoj9Xvrxlg7P%M8_jhCB6{ZeMHBbV;*wbj{FIczdNqu{KyT*b=(m7+*?lWsNL2W zANS&M9cSL{LHav0$KE9~vBQzgKI1!7|Icw93is{!Qb*&v#`V8dIJqMi)fgVjbVix_ zaUDO4s?%wcJGMlH<7V#2#FxuVnAx${osIk6a^36i8n@TXj$@ar&9lagj&aKhm70pEf4JIy0g)XeUI;WEh?P&R^k48^zJ_)wp7R;SyVpx_>Rx_Y zruMmyMF)pw|)@MUwODsw7qs*l~bg5etqEs|C_$%ZRM?FcWzYg?6;*acw3zd z-d29`+tQ2Pmd@=+M?VYtA^B~cEq+_2@4YR(>}}~g-#gz z+tR<3ZrO9kgl8W<<$q`So3~Xu?rn|!;pj(y_5H@*>^83L@s8{6Z9H)IrfrjAqT_*k z8xMYG^WnZ{i&-7d-`jZ5Zj0kSl;a(5-s>~m_nhXlI}ZJ^q;H$c7IvIEmh4>Eu_#Jj z6aB$N$K7Me6_(); for (TLRPC.PhotoSize size : messageOwner.action.photo.sizes) { - photoThumbs.add(new PhotoObject(size, preview)); + photoThumbs.add(new PhotoObject(size, preview, isSecretMedia())); } } else if (photoThumbs != null && !photoThumbs.isEmpty()) { for (PhotoObject photoObject : photoThumbs) { @@ -361,7 +362,7 @@ public class MessageObject { if (!update) { photoThumbs = new ArrayList(); for (TLRPC.PhotoSize size : messageOwner.media.photo.sizes) { - PhotoObject obj = new PhotoObject(size, preview); + PhotoObject obj = new PhotoObject(size, preview, isSecretMedia()); photoThumbs.add(obj); if (imagePreview == null && obj.image != null) { imagePreview = obj.image; @@ -383,7 +384,7 @@ public class MessageObject { } else if (messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { if (!update) { photoThumbs = new ArrayList(); - PhotoObject obj = new PhotoObject(messageOwner.media.video.thumb, preview); + PhotoObject obj = new PhotoObject(messageOwner.media.video.thumb, preview, isSecretMedia()); photoThumbs.add(obj); if (imagePreview == null && obj.image != null) { imagePreview = obj.image; @@ -396,7 +397,7 @@ public class MessageObject { if (!(messageOwner.media.document.thumb instanceof TLRPC.TL_photoSizeEmpty)) { if (!update) { photoThumbs = new ArrayList(); - PhotoObject obj = new PhotoObject(messageOwner.media.document.thumb, preview); + PhotoObject obj = new PhotoObject(messageOwner.media.document.thumb, preview, isSecretMedia()); photoThumbs.add(obj); } else if (photoThumbs != null && !photoThumbs.isEmpty() && messageOwner.media.document.thumb != null) { PhotoObject photoObject = photoThumbs.get(0); @@ -599,15 +600,39 @@ public class MessageObject { } public boolean isOut() { - return messageOwner.out; + return (messageOwner.flags & TLRPC.MESSAGE_FLAG_OUT) != 0; } public boolean isFromMe() { return messageOwner.from_id == UserConfig.getClientUserId(); } - public boolean isUnread () { - return messageOwner.unread; + public boolean isUnread() { + return (messageOwner.flags & TLRPC.MESSAGE_FLAG_UNREAD) != 0; + } + + public void setIsRead() { + messageOwner.flags &=~ TLRPC.MESSAGE_FLAG_UNREAD; + } + + public boolean isSecretMedia() { + return messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && messageOwner.ttl != 0; + } + + public static void setIsUnread(TLRPC.Message message, boolean unread) { + if (unread) { + message.flags |= TLRPC.MESSAGE_FLAG_UNREAD; + } else { + message.flags &=~ TLRPC.MESSAGE_FLAG_UNREAD; + } + } + + public static boolean isUnread(TLRPC.Message message) { + return (message.flags & TLRPC.MESSAGE_FLAG_UNREAD) != 0; + } + + public static boolean isOut(TLRPC.Message message) { + return (message.flags & TLRPC.MESSAGE_FLAG_OUT) != 0; } public long getDialogId() { @@ -635,4 +660,25 @@ public class MessageObject { public boolean isSent() { return messageOwner.send_state == MESSAGE_SEND_STATE_SENT; } + + public String getSecretTimeString() { + if (!isSecretMedia()) { + return null; + } + int secondsLeft = messageOwner.ttl; + if (messageOwner.destroyTime != 0) { + secondsLeft = Math.max(0, messageOwner.destroyTime - ConnectionsManager.getInstance().getCurrentTime()); + } + String str; + if (secondsLeft < 60) { + str = secondsLeft + "s"; + } else if (secondsLeft < 60 * 60) { + str = secondsLeft / 60 + "m"; + } else if (secondsLeft < 60 * 60 * 24) { + str = secondsLeft / 60 / 60 + "h"; + } else { + str = secondsLeft / 60 / 60 / 24 + "d"; + } + return str; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java index 8908da7b..1fdba71a 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java @@ -1649,6 +1649,28 @@ public class MessagesController implements NotificationCenter.NotificationCenter }); } + public void markMessageAsRead(final long dialog_id, final long random_id) { + if (random_id == 0 || dialog_id == 0) { + return; + } + int lower_part = (int)dialog_id; + int high_id = (int)(dialog_id >> 32); + if (lower_part != 0) { + return; + } + TLRPC.EncryptedChat chat = getEncryptedChat(high_id); + if (chat == null) { + return; + } + ArrayList random_ids = new ArrayList(); + random_ids.add(random_id); + SendMessagesHelper.getInstance().sendMessagesReadMessage(random_ids, chat); + if (chat.ttl > 0) { + MessagesStorage.getInstance().createTaskForSecretChat(chat.id, 0, ConnectionsManager.getInstance().getCurrentTime(), 0, random_ids); + } + //TODO resend request + } + public void markDialogAsRead(final long dialog_id, final int max_id, final int max_positive_id, final int offset, final int max_date, final boolean was, final boolean popup) { int lower_part = (int)dialog_id; int high_id = (int)(dialog_id >> 32); @@ -1762,18 +1784,17 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (chat.ttl > 0 && was) { int serverTime = Math.max(ConnectionsManager.getInstance().getCurrentTime(), max_date); - MessagesStorage.getInstance().createTaskForDate(chat.id, serverTime, serverTime, 0); + MessagesStorage.getInstance().createTaskForSecretChat(chat.id, serverTime, serverTime, 0, null); } } } private void processPendingEncMessages() { - if (pendingEncMessagesToDelete.isEmpty()) { - return; + if (!pendingEncMessagesToDelete.isEmpty()) { + ArrayList arr = new ArrayList(pendingEncMessagesToDelete); + MessagesStorage.getInstance().markMessagesAsDeletedByRandoms(arr); + pendingEncMessagesToDelete.clear(); } - ArrayList arr = new ArrayList(pendingEncMessagesToDelete); - MessagesStorage.getInstance().markMessagesAsDeletedByRandoms(arr); - pendingEncMessagesToDelete.clear(); } public long createChat(String title, ArrayList selectedContacts, final TLRPC.InputFile uploadedAvatar, boolean isBroadcast) { @@ -1809,11 +1830,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter newMsg.action = new TLRPC.TL_messageActionCreatedBroadcastList(); newMsg.local_id = newMsg.id = UserConfig.getNewMessageId(); newMsg.from_id = UserConfig.getClientUserId(); - newMsg.unread = false; newMsg.dialog_id = AndroidUtilities.makeBroadcastId(chat.id); newMsg.to_id = new TLRPC.TL_peerChat(); newMsg.to_id.chat_id = chat.id; - newMsg.out = false; newMsg.date = ConnectionsManager.getInstance().getCurrentTime(); newMsg.random_id = 0; UserConfig.saveConfig(false); @@ -2576,7 +2595,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter message.message = updates.message; message.date = updates.date; message.flags = TLRPC.MESSAGE_FLAG_UNREAD; - message.unread = true; message.media = new TLRPC.TL_messageMediaEmpty(); MessagesStorage.lastSeqValue = updates.seq; MessagesStorage.lastPtsValue = updates.pts; @@ -2641,7 +2659,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter message.to_id.user_id = updates.from_id; message.message = updates.message; message.date = updates.date; - message.unread = true; message.flags = TLRPC.MESSAGE_FLAG_UNREAD; message.media = new TLRPC.TL_messageMediaEmpty(); MessagesStorage.lastSeqValue = updates.seq; @@ -2920,13 +2937,11 @@ public class MessagesController implements NotificationCenter.NotificationCenter newMessage.action = new TLRPC.TL_messageActionUserJoined(); newMessage.local_id = newMessage.id = UserConfig.getNewMessageId(); UserConfig.saveConfig(false); - newMessage.unread = true; newMessage.flags = TLRPC.MESSAGE_FLAG_UNREAD; newMessage.date = update.date; newMessage.from_id = update.user_id; newMessage.to_id = new TLRPC.TL_peerUser(); newMessage.to_id.user_id = UserConfig.getClientUserId(); - newMessage.out = false; newMessage.dialog_id = update.user_id; messagesArr.add(newMessage); @@ -2966,13 +2981,11 @@ public class MessagesController implements NotificationCenter.NotificationCenter newMessage.action.address = update.location; newMessage.local_id = newMessage.id = UserConfig.getNewMessageId(); UserConfig.saveConfig(false); - newMessage.unread = true; newMessage.flags = TLRPC.MESSAGE_FLAG_UNREAD; newMessage.date = update.date; newMessage.from_id = 777000; newMessage.to_id = new TLRPC.TL_peerUser(); newMessage.to_id.user_id = UserConfig.getClientUserId(); - newMessage.out = false; newMessage.dialog_id = 777000; messagesArr.add(newMessage); @@ -3301,7 +3314,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter for (Integer id : markAsReadMessages) { MessageObject obj = dialogMessage.get(id); if (obj != null) { - obj.messageOwner.unread = false; + obj.setIsRead(); updateMask |= UPDATE_MASK_READ_DIALOG_MESSAGE; } } @@ -3314,7 +3327,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (dialog != null) { MessageObject message = dialogMessage.get(dialog.top_message); if (message != null && message.messageOwner.date <= entry.getValue()) { - message.messageOwner.unread = false; + message.setIsRead(); updateMask |= UPDATE_MASK_READ_DIALOG_MESSAGE; } } @@ -3351,7 +3364,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } if (!tasks.isEmpty()) { for (TLRPC.TL_updateEncryptedMessagesRead update : tasks) { - MessagesStorage.getInstance().createTaskForDate(update.chat_id, update.max_date, update.date, 1); + MessagesStorage.getInstance().createTaskForSecretChat(update.chat_id, update.max_date, update.date, 1, null); } } @@ -3504,7 +3517,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (object instanceof TLRPC.TL_decryptedMessage) { TLRPC.TL_decryptedMessage decryptedMessage = (TLRPC.TL_decryptedMessage)object; - TLRPC.TL_message newMessage = new TLRPC.TL_message(); + TLRPC.TL_message_secret newMessage = new TLRPC.TL_message_secret(); newMessage.message = decryptedMessage.message; newMessage.date = message.date; newMessage.local_id = newMessage.id = UserConfig.getNewMessageId(); @@ -3514,8 +3527,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter newMessage.random_id = message.random_id; newMessage.to_id.user_id = UserConfig.getClientUserId(); newMessage.flags = TLRPC.MESSAGE_FLAG_UNREAD; - newMessage.out = false; - newMessage.unread = true; newMessage.dialog_id = ((long)chat.id) << 32; newMessage.ttl = chat.ttl; if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaEmpty) { @@ -3663,12 +3674,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter newMessage.local_id = newMessage.id = UserConfig.getNewMessageId(); UserConfig.saveConfig(false); newMessage.flags = TLRPC.MESSAGE_FLAG_UNREAD; - newMessage.unread = true; newMessage.date = message.date; newMessage.from_id = from_id; newMessage.to_id = new TLRPC.TL_peerUser(); newMessage.to_id.user_id = UserConfig.getClientUserId(); - newMessage.out = false; newMessage.dialog_id = ((long)chat.id) << 32; MessagesStorage.getInstance().updateEncryptedChatTTL(chat); return newMessage; @@ -3707,6 +3716,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter pendingEncMessagesToDelete.addAll(serviceMessage.action.random_ids); } return null; + } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionReadMessages) { + if (!serviceMessage.action.random_ids.isEmpty()) { + MessagesStorage.getInstance().createTaskForSecretChat(chat.id, 0, message.date, 1, serviceMessage.action.random_ids); + } } else { return null; } diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java index 5283acb0..b93081e0 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java @@ -282,7 +282,7 @@ public class MessagesStorage { database.executeFast("DROP INDEX IF EXISTS date_idx_enc_tasks;").stepThis().dispose(); database.executeFast("DROP TABLE IF EXISTS enc_tasks;").stepThis().dispose(); - database.executeFast("ALTER TABLE messages ADD COLUMN media INTEGER").stepThis().dispose(); + database.executeFast("ALTER TABLE messages ADD COLUMN media INTEGER default 0").stepThis().dispose(); database.executeFast("PRAGMA user_version = 6").stepThis().dispose(); } } catch (Exception e) { @@ -428,8 +428,7 @@ public class MessagesStorage { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(1)); if (data != null && cursor.byteBufferValue(1, data.buffer) != 0) { TLRPC.Message message = (TLRPC.Message)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - int read_state = cursor.intValue(0); - message.unread = (cursor.intValue(0) != 1); + MessageObject.setIsUnread(message, cursor.intValue(0) != 1); message.id = cursor.intValue(3); message.date = cursor.intValue(4); message.dialog_id = cursor.longValue(5); @@ -470,7 +469,7 @@ public class MessagesStorage { userIds.add(message.fwd_from_id); } message.send_state = cursor.intValue(2); - if (!message.unread && lower_id != 0 || message.id > 0) { + if (!MessageObject.isUnread(message) && lower_id != 0 || message.id > 0) { message.send_state = 0; } if (lower_id == 0 && !cursor.isNull(5)) { @@ -836,7 +835,7 @@ public class MessagesStorage { }); } - public void createTaskForDate(final int chat_id, final int time, final int readTime, final int isOut) { + public void createTaskForSecretChat(final int chat_id, final int time, final int readTime, final int isOut, final ArrayList random_ids) { storageQueue.postRunnable(new Runnable() { @Override public void run() { @@ -844,7 +843,13 @@ public class MessagesStorage { int minDate = Integer.MAX_VALUE; SparseArray> messages = new SparseArray>(); StringBuilder mids = new StringBuilder(); - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid, ttl FROM messages WHERE uid = %d AND out = %d AND read_state = 1 AND ttl > 0 AND date <= %d AND send_state = 0 AND media != 1", ((long)chat_id) << 32, isOut, time)); + SQLiteCursor cursor = null; + if (random_ids == null) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid, ttl FROM messages WHERE uid = %d AND out = %d AND read_state = 1 AND ttl > 0 AND date <= %d AND send_state = 0 AND media != 1", ((long) chat_id) << 32, isOut, time)); + } else { + String ids = TextUtils.join(",", random_ids); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.mid, m.ttl FROM messages as m INNER JOIN randoms as r ON m.mid = r.mid WHERE r.random_id IN (%s)", ids)); + } while (cursor.next()) { int mid = cursor.intValue(0); int date = readTime + cursor.intValue(1); @@ -1640,8 +1645,7 @@ public class MessagesStorage { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(1)); if (data != null && cursor.byteBufferValue(1, data.buffer) != 0) { TLRPC.Message message = (TLRPC.Message)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - int read_state = cursor.intValue(0); - message.unread = (cursor.intValue(0) != 1); + MessageObject.setIsUnread(message, cursor.intValue(0) != 1); message.id = cursor.intValue(3); message.date = cursor.intValue(4); if (!cursor.isNull(5)) { @@ -1691,7 +1695,7 @@ public class MessagesStorage { userIds.add(message.fwd_from_id); } message.send_state = cursor.intValue(2); - if (!message.unread && lower_id != 0 || message.id > 0) { + if (!MessageObject.isUnread(message) && lower_id != 0 || message.id > 0) { message.send_state = 0; } if (lower_id == 0 && !cursor.isNull(5)) { @@ -1879,8 +1883,7 @@ public class MessagesStorage { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(1)); if (data != null && cursor.byteBufferValue(1, data.buffer) != 0) { TLRPC.Message message = (TLRPC.Message)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - int read_state = cursor.intValue(0); - message.unread = (cursor.intValue(0) != 1); + MessageObject.setIsUnread(message, cursor.intValue(0) != 1); message.id = cursor.intValue(3); message.date = cursor.intValue(4); message.dialog_id = dialog_id; @@ -1899,12 +1902,23 @@ public class MessagesStorage { fromUser.add(message.fwd_from_id); } message.send_state = cursor.intValue(2); - if (!message.unread && lower_id != 0 || message.id > 0) { + if (!MessageObject.isUnread(message) && lower_id != 0 || message.id > 0) { message.send_state = 0; } if (lower_id == 0 && !cursor.isNull(5)) { message.random_id = cursor.longValue(5); } + if ((int)dialog_id == 0 && message.media != null && message.media.photo != null) { + try { + SQLiteCursor cursor2 = database.queryFinalized(String.format(Locale.US, "SELECT date FROM enc_tasks_v2 WHERE mid = %d", message.id)); + if (cursor2.next()) { + message.destroyTime = cursor2.intValue(0); + } + cursor2.dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } } buffersStorage.reuseFreeBuffer(data); @@ -2456,7 +2470,7 @@ public class MessagesStorage { } } - if (message.unread && !message.out) { + if (MessageObject.isUnread(message) && !MessageObject.isOut(message)) { if (messageIds.length() > 0) { messageIds.append(","); } @@ -2532,11 +2546,11 @@ public class MessagesStorage { } state.bindInteger(1, messageId); state.bindLong(2, dialog_id); - state.bindInteger(3, (message.unread ? 0 : 1)); + state.bindInteger(3, (MessageObject.isUnread(message) ? 0 : 1)); state.bindInteger(4, message.send_state); state.bindInteger(5, message.date); state.bindByteBuffer(6, data.buffer); - state.bindInteger(7, (message.out ? 1 : 0)); + state.bindInteger(7, (MessageObject.isOut(message) ? 1 : 0)); state.bindInteger(8, message.ttl); state.bindInteger(9, getMessageMediaType(message)); state.step(); @@ -3061,7 +3075,7 @@ public class MessagesStorage { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(4)); if (data != null && cursor.byteBufferValue(4, data.buffer) != 0) { TLRPC.Message message = (TLRPC.Message)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - message.unread = (cursor.intValue(5) != 1); + MessageObject.setIsUnread(message, cursor.intValue(5) != 1); message.id = cursor.intValue(6); message.send_state = cursor.intValue(7); dialogs.messages.add(message); @@ -3218,11 +3232,11 @@ public class MessagesStorage { message.serializeToStream(data); state.bindInteger(1, message.id); state.bindLong(2, dialog_id); - state.bindInteger(3, (message.unread ? 0 : 1)); + state.bindInteger(3, (MessageObject.isUnread(message) ? 0 : 1)); state.bindInteger(4, message.send_state); state.bindInteger(5, message.date); state.bindByteBuffer(6, data.buffer); - state.bindInteger(7, (message.out ? 1 : 0)); + state.bindInteger(7, (MessageObject.isOut(message) ? 1 : 0)); state.bindInteger(8, 0); state.bindInteger(9, getMessageMediaType(message)); state.step(); @@ -3316,7 +3330,7 @@ public class MessagesStorage { if (data != null && cursor.byteBufferValue(4, data.buffer) != 0) { TLRPC.Message message = (TLRPC.Message)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); if (message != null) { - message.unread = (cursor.intValue(5) != 1); + MessageObject.setIsUnread(message, cursor.intValue(5) != 1); message.id = cursor.intValue(6); message.send_state = cursor.intValue(7); dialogs.messages.add(message); @@ -3485,11 +3499,11 @@ public class MessagesStorage { state.bindInteger(1, message.id); state.bindInteger(2, uid); - state.bindInteger(3, (message.unread ? 0 : 1)); + state.bindInteger(3, (MessageObject.isUnread(message) ? 0 : 1)); state.bindInteger(4, message.send_state); state.bindInteger(5, message.date); state.bindByteBuffer(6, data.buffer); - state.bindInteger(7, (message.out ? 1 : 0)); + state.bindInteger(7, (MessageObject.isOut(message) ? 1 : 0)); state.bindInteger(8, 0); state.bindInteger(9, getMessageMediaType(message)); state.step(); diff --git a/TMessagesProj/src/main/java/org/telegram/android/NativeLoader.java b/TMessagesProj/src/main/java/org/telegram/android/NativeLoader.java index c52d3431..7a7499b0 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/NativeLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/android/NativeLoader.java @@ -24,9 +24,9 @@ import java.util.zip.ZipFile; public class NativeLoader { private static final long sizes[] = new long[] { - 951052, //armeabi - 1032992, //armeabi-v7a - 1612020, //x86 + 955148, //armeabi + 1041184, //armeabi-v7a + 1616116, //x86 0, //mips }; diff --git a/TMessagesProj/src/main/java/org/telegram/android/PhotoObject.java b/TMessagesProj/src/main/java/org/telegram/android/PhotoObject.java index afa2b95b..fb7ac51c 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/PhotoObject.java +++ b/TMessagesProj/src/main/java/org/telegram/android/PhotoObject.java @@ -21,7 +21,7 @@ public class PhotoObject { public TLRPC.PhotoSize photoOwner; public Bitmap image; - public PhotoObject(TLRPC.PhotoSize photo, int preview) { + public PhotoObject(TLRPC.PhotoSize photo, int preview, boolean secret) { photoOwner = photo; if (preview != 0 && photo instanceof TLRPC.TL_photoCachedSize) { @@ -34,7 +34,13 @@ public class PhotoObject { image = BitmapFactory.decodeByteArray(photoOwner.bytes, 0, photoOwner.bytes.length, opts); if (image != null) { if (preview == 2) { - Utilities.blurBitmap(image); + if (secret) { + Utilities.blurBitmap(image, 7); + Utilities.blurBitmap(image, 7); + Utilities.blurBitmap(image, 7); + } else { + Utilities.blurBitmap(image, 3); + } } if (ImageLoader.getInstance().runtimeHack != null) { ImageLoader.getInstance().runtimeHack.trackFree(image.getRowBytes() * image.getHeight()); diff --git a/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java index 990ce178..ff2a5e90 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java @@ -364,6 +364,9 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter private int sendMessage(String message, double lat, double lon, TLRPC.TL_photo photo, TLRPC.TL_video video, MessageObject msgObj, TLRPC.User user, TLRPC.TL_document document, TLRPC.TL_audio audio, String originalPath, long peer, boolean retry, String path) { TLRPC.Message newMsg = null; int type = -1; + int lower_id = (int) peer; + int high_id = (int) (peer >> 32); + if (retry) { newMsg = msgObj.messageOwner; @@ -409,12 +412,20 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } } else { if (message != null) { - newMsg = new TLRPC.TL_message(); + if (lower_id != 0) { + newMsg = new TLRPC.TL_message(); + } else { + newMsg = new TLRPC.TL_message_secret(); + } newMsg.media = new TLRPC.TL_messageMediaEmpty(); type = 0; newMsg.message = message; } else if (lat != 0 && lon != 0) { - newMsg = new TLRPC.TL_message(); + if (lower_id != 0) { + newMsg = new TLRPC.TL_message(); + } else { + newMsg = new TLRPC.TL_message_secret(); + } newMsg.media = new TLRPC.TL_messageMediaGeo(); newMsg.media.geo = new TLRPC.TL_geoPoint(); newMsg.media.geo.lat = lat; @@ -422,7 +433,11 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter newMsg.message = ""; type = 1; } else if (photo != null) { - newMsg = new TLRPC.TL_message(); + if (lower_id != 0) { + newMsg = new TLRPC.TL_message(); + } else { + newMsg = new TLRPC.TL_message_secret(); + } newMsg.media = new TLRPC.TL_messageMediaPhoto(); newMsg.media.photo = photo; type = 2; @@ -430,7 +445,11 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter TLRPC.FileLocation location1 = photo.sizes.get(photo.sizes.size() - 1).location; newMsg.attachPath = FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE) + "/" + location1.volume_id + "_" + location1.local_id + ".jpg"; } else if (video != null) { - newMsg = new TLRPC.TL_message(); + if (lower_id != 0) { + newMsg = new TLRPC.TL_message(); + } else { + newMsg = new TLRPC.TL_message_secret(); + } newMsg.media = new TLRPC.TL_messageMediaVideo(); newMsg.media.video = video; newMsg.videoEditedInfo = video.videoEditedInfo; @@ -461,7 +480,11 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter type = 4; } } else if (user != null) { - newMsg = new TLRPC.TL_message(); + if (lower_id != 0) { + newMsg = new TLRPC.TL_message(); + } else { + newMsg = new TLRPC.TL_message_secret(); + } newMsg.media = new TLRPC.TL_messageMediaContact(); newMsg.media.phone_number = user.phone; newMsg.media.first_name = user.first_name; @@ -470,14 +493,22 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter newMsg.message = ""; type = 6; } else if (document != null) { - newMsg = new TLRPC.TL_message(); + if (lower_id != 0) { + newMsg = new TLRPC.TL_message(); + } else { + newMsg = new TLRPC.TL_message_secret(); + } newMsg.media = new TLRPC.TL_messageMediaDocument(); newMsg.media.document = document; type = 7; newMsg.message = "-1"; newMsg.attachPath = path; } else if (audio != null) { - newMsg = new TLRPC.TL_message(); + if (lower_id != 0) { + newMsg = new TLRPC.TL_message(); + } else { + newMsg = new TLRPC.TL_message_secret(); + } newMsg.media = new TLRPC.TL_messageMediaAudio(); newMsg.media.audio = audio; type = 8; @@ -487,7 +518,6 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter newMsg.local_id = newMsg.id = UserConfig.getNewMessageId(); newMsg.from_id = UserConfig.getClientUserId(); newMsg.flags |= TLRPC.MESSAGE_FLAG_OUT; - newMsg.out = true; UserConfig.saveConfig(false); } if (newMsg.random_id == 0) { @@ -495,10 +525,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } newMsg.date = ConnectionsManager.getInstance().getCurrentTime(); newMsg.flags |= TLRPC.MESSAGE_FLAG_UNREAD; - newMsg.unread = true; newMsg.dialog_id = peer; - int lower_id = (int) peer; - int high_id = (int) (peer >> 32); TLRPC.EncryptedChat encryptedChat = null; TLRPC.InputPeer sendToPeer = null; ArrayList sendToPeers = null; @@ -1405,6 +1432,19 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } } + public void sendMessagesReadMessage(ArrayList random_ids, TLRPC.EncryptedChat encryptedChat) { + if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { + return; + } + TLRPC.TL_decryptedMessageService_old reqSend = new TLRPC.TL_decryptedMessageService_old(); + reqSend.random_id = getNextRandomId(); + reqSend.random_bytes = new byte[Math.max(1, (int)Math.ceil(Utilities.random.nextDouble() * 16))]; + Utilities.random.nextBytes(reqSend.random_bytes); + reqSend.action = new TLRPC.TL_decryptedMessageActionReadMessages(); + reqSend.action.random_ids = random_ids; + performSendEncryptedRequest(reqSend, null, encryptedChat, null, null); + } + public void sendMessagesDeleteMessage(ArrayList random_ids, TLRPC.EncryptedChat encryptedChat) { if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { return; @@ -1440,7 +1480,6 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter newMsg.action.ttl = encryptedChat.ttl; newMsg.local_id = newMsg.id = UserConfig.getNewMessageId(); newMsg.from_id = UserConfig.getClientUserId(); - newMsg.unread = true; newMsg.flags = TLRPC.MESSAGE_FLAG_UNREAD | TLRPC.MESSAGE_FLAG_OUT; newMsg.dialog_id = ((long)encryptedChat.id) << 32; newMsg.to_id = new TLRPC.TL_peerUser(); @@ -1449,7 +1488,6 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } else { newMsg.to_id.user_id = encryptedChat.participant_id; } - newMsg.out = true; newMsg.date = ConnectionsManager.getInstance().getCurrentTime(); newMsg.random_id = getNextRandomId(); UserConfig.saveConfig(false); @@ -1488,7 +1526,6 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter newMsg.local_id = newMsg.id = UserConfig.getNewMessageId(); newMsg.from_id = UserConfig.getClientUserId(); - newMsg.unread = true; newMsg.flags = TLRPC.MESSAGE_FLAG_UNREAD | TLRPC.MESSAGE_FLAG_OUT; newMsg.dialog_id = ((long)encryptedChat.id) << 32; newMsg.to_id = new TLRPC.TL_peerUser(); @@ -1497,7 +1534,6 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } else { newMsg.to_id.user_id = encryptedChat.participant_id; } - newMsg.out = true; newMsg.date = ConnectionsManager.getInstance().getCurrentTime(); newMsg.random_id = getNextRandomId(); UserConfig.saveConfig(false); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java b/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java index a1c538a4..755deabc 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java @@ -997,6 +997,10 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. return (int)(System.currentTimeMillis() / 1000) + timeDifference; } + public int getTimeDifference() { + return timeDifference; + } + private void processRequestQueue(int requestClass, int _datacenterId) { boolean haveNetwork = true;//isNetworkOnline(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TLClassStore.java b/TMessagesProj/src/main/java/org/telegram/messenger/TLClassStore.java index 164abd92..2e2f9452 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TLClassStore.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TLClassStore.java @@ -362,6 +362,7 @@ public class TLClassStore { classStore.put(TLRPC.TL_messageService_old.constructor, TLRPC.TL_messageService_old.class); classStore.put(TLRPC.TL_decryptedMessageService_old.constructor, TLRPC.TL_decryptedMessageService_old.class); classStore.put(TLRPC.TL_decryptedMessage_old.constructor, TLRPC.TL_decryptedMessage_old.class); + classStore.put(TLRPC.TL_message_secret.constructor, TLRPC.TL_message_secret.class); } static TLClassStore store = null; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java index 7a6950aa..e86ad58f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java @@ -8769,8 +8769,6 @@ public class TLRPC { public int fwd_date; public int from_id; public Peer to_id; - public boolean out; - public boolean unread; public int date; public String message; public MessageMedia media; @@ -8782,6 +8780,7 @@ public class TLRPC { public int local_id = 0; public long dialog_id; public int ttl; + public int destroyTime; public VideoEditedInfo videoEditedInfo = null; } @@ -8799,8 +8798,6 @@ public class TLRPC { date = stream.readInt32(); message = stream.readString(); media = (MessageMedia)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); - out = (flags & MESSAGE_FLAG_OUT) != 0; - unread = (flags & MESSAGE_FLAG_UNREAD) != 0; if (id < 0) { fwd_msg_id = stream.readInt32(); } @@ -8843,8 +8840,6 @@ public class TLRPC { date = stream.readInt32(); message = stream.readString(); media = (MessageMedia)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); - out = (flags & 2) != 0; - unread = (flags & 1) != 0; if (id < 0 || (media != null && !(media instanceof TL_messageMediaEmpty) && message != null && message.length() != 0 && message.startsWith("-1"))) { attachPath = stream.readString(); } @@ -8878,8 +8873,6 @@ public class TLRPC { to_id = (Peer)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); date = stream.readInt32(); action = (MessageAction)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); - out = (flags & 2) != 0; - unread = (flags & 1) != 0; } public void serializeToStream(AbsSerializedData stream) { @@ -8901,8 +8894,8 @@ public class TLRPC { id = stream.readInt32(); from_id = stream.readInt32(); to_id = (Peer)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); - out = stream.readBool(); - unread = stream.readBool(); + flags |= stream.readBool() ? MESSAGE_FLAG_OUT : 0; + flags |= stream.readBool() ? MESSAGE_FLAG_UNREAD : 0; date = stream.readInt32(); action = (MessageAction)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); } @@ -8912,8 +8905,8 @@ public class TLRPC { stream.writeInt32(id); stream.writeInt32(from_id); to_id.serializeToStream(stream); - stream.writeBool(out); - stream.writeBool(unread); + stream.writeBool((flags & MESSAGE_FLAG_OUT) != 0); + stream.writeBool((flags & MESSAGE_FLAG_UNREAD) != 0); stream.writeInt32(date); action.serializeToStream(stream); } @@ -8929,8 +8922,8 @@ public class TLRPC { fwd_date = stream.readInt32(); from_id = stream.readInt32(); to_id = (Peer)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); - out = stream.readBool(); - unread = stream.readBool(); + flags |= stream.readBool() ? MESSAGE_FLAG_OUT : 0; + flags |= stream.readBool() ? MESSAGE_FLAG_UNREAD : 0; date = stream.readInt32(); message = stream.readString(); media = (MessageMedia)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); @@ -8953,8 +8946,8 @@ public class TLRPC { stream.writeInt32(fwd_date); stream.writeInt32(from_id); to_id.serializeToStream(stream); - stream.writeBool(out); - stream.writeBool(unread); + stream.writeBool((flags & MESSAGE_FLAG_OUT) != 0); + stream.writeBool((flags & MESSAGE_FLAG_UNREAD) != 0); stream.writeInt32(date); stream.writeString(message); media.serializeToStream(stream); @@ -8972,8 +8965,8 @@ public class TLRPC { id = stream.readInt32(); from_id = stream.readInt32(); to_id = (Peer)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); - out = stream.readBool(); - unread = stream.readBool(); + flags |= stream.readBool() ? MESSAGE_FLAG_OUT : 0; + flags |= stream.readBool() ? MESSAGE_FLAG_UNREAD : 0; date = stream.readInt32(); message = stream.readString(); media = (MessageMedia)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); @@ -8991,8 +8984,8 @@ public class TLRPC { stream.writeInt32(id); stream.writeInt32(from_id); to_id.serializeToStream(stream); - stream.writeBool(out); - stream.writeBool(unread); + stream.writeBool((flags & MESSAGE_FLAG_OUT) != 0); + stream.writeBool((flags & MESSAGE_FLAG_UNREAD) != 0); stream.writeInt32(date); stream.writeString(message); media.serializeToStream(stream); @@ -9004,11 +8997,11 @@ public class TLRPC { public static int constructor = 0x555555F8; public void readParams(AbsSerializedData stream) { + flags = stream.readInt32(); id = stream.readInt32(); + ttl = stream.readInt32(); from_id = stream.readInt32(); to_id = (Peer)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); - out = stream.readBool(); - unread = stream.readBool(); date = stream.readInt32(); message = stream.readString(); media = (MessageMedia)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); @@ -9023,11 +9016,11 @@ public class TLRPC { public void serializeToStream(AbsSerializedData stream) { stream.writeInt32(constructor); + stream.writeInt32(flags); stream.writeInt32(id); + stream.writeInt32(ttl); stream.writeInt32(from_id); to_id.serializeToStream(stream); - stream.writeBool(out); - stream.writeBool(unread); stream.writeInt32(date); stream.writeString(message); media.serializeToStream(stream); @@ -9773,7 +9766,7 @@ public class TLRPC { } public static class TL_decryptedMessageActionScreenshotMessages extends DecryptedMessageAction { - public static int constructor = 0x954bd30; + public static int constructor = 0x8ac1f475; public void readParams(AbsSerializedData stream) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java index 02815f5c..998079ff 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java @@ -28,7 +28,6 @@ import net.hockeyapp.android.CrashManager; import net.hockeyapp.android.CrashManagerListener; import net.hockeyapp.android.UpdateManager; -import org.telegram.android.LocaleController; import org.telegram.ui.ApplicationLoader; import java.io.ByteArrayInputStream; @@ -112,7 +111,7 @@ public class Utilities { public native static long doPQNative(long _what); public native static void loadBitmap(String path, int[] bitmap, int scale, int format, int width, int height); - public native static void blurBitmap(Object bitmap); + public native static void blurBitmap(Object bitmap, int radius); public native static int convertVideoFrame(ByteBuffer src, ByteBuffer dest, int destFormat, int width, int height, int padding, int swap); private native static void aesIgeEncryption(ByteBuffer buffer, byte[] key, byte[] iv, boolean encrypt, int offset, int length); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java index 54d96e86..f1abc028 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java @@ -25,6 +25,7 @@ import android.view.animation.DecelerateInterpolator; import org.telegram.android.AndroidUtilities; import org.telegram.android.ImageLoader; import org.telegram.android.LocaleController; +import org.telegram.messenger.ConnectionsManager; import org.telegram.messenger.FileLoader; import org.telegram.android.MediaController; import org.telegram.messenger.R; @@ -41,7 +42,9 @@ import java.util.Locale; public class ChatMediaCell extends ChatBaseCell implements MediaController.FileDownloadProgressListener { public static interface ChatMediaCellDelegate { - public abstract void didPressedImage(ChatMediaCell cell); + public abstract boolean didPressedImage(ChatMediaCell cell); + public abstract void didUnpressedImage(ChatMediaCell cell); + public abstract void didClickedImage(ChatMediaCell cell); public abstract void didPressedOther(ChatMediaCell cell); } @@ -52,13 +55,14 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD private static Drawable videoIconDrawable; private static Drawable docMenuInDrawable; private static Drawable docMenuOutDrawable; - private static Drawable[] buttonStatesDrawables = new Drawable[5]; + private static Drawable[] buttonStatesDrawables = new Drawable[8]; private static Drawable[][] buttonStatesDrawablesDoc = new Drawable[3][2]; private static TextPaint infoPaint; private static MessageObject lastDownloadedGifMessage = null; private static TextPaint namePaint; private static Paint docBackPaint; private static Paint progressPaint; + private static Paint deleteProgressPaint; private static DecelerateInterpolator decelerateInterpolator; private GifDrawable gifDrawable = null; @@ -81,6 +85,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD private boolean otherPressed = false; private int buttonX; private int buttonY; + private boolean listenForUnpressed = false; private StaticLayout infoLayout; private int infoWidth; @@ -101,6 +106,8 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD private float animatedProgressValue = 0; private long currentProgressTime = 0; private float animationProgressStart = 0; + private RectF deleteProgressRect = new RectF(); + private int lastSecretSecondsLeft = 0; public ChatMediaCell(Context context) { super(context); @@ -115,6 +122,9 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD buttonStatesDrawables[2] = getResources().getDrawable(R.drawable.photogif); buttonStatesDrawables[3] = getResources().getDrawable(R.drawable.playvideo); buttonStatesDrawables[4] = getResources().getDrawable(R.drawable.photopause); + buttonStatesDrawables[5] = getResources().getDrawable(R.drawable.burn); + buttonStatesDrawables[6] = getResources().getDrawable(R.drawable.circle); + buttonStatesDrawables[7] = getResources().getDrawable(R.drawable.photocheck); buttonStatesDrawablesDoc[0][0] = getResources().getDrawable(R.drawable.docload_b); buttonStatesDrawablesDoc[1][0] = getResources().getDrawable(R.drawable.doccancel_b); buttonStatesDrawablesDoc[2][0] = getResources().getDrawable(R.drawable.docpause_b); @@ -139,6 +149,9 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD progressPaint.setStrokeCap(Paint.Cap.ROUND); progressPaint.setStrokeWidth(AndroidUtilities.dp(2)); + deleteProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + deleteProgressPaint.setColor(0xffe4e2e0); + decelerateInterpolator = new DecelerateInterpolator(); } @@ -199,7 +212,11 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD } } } - if (result) { + listenForUnpressed = false; + if (imagePressed && mediaDelegate != null && mediaDelegate.didPressedImage(this)) { + imagePressed = false; + listenForUnpressed = true; + } else if (result) { startCheckLongPress(); } } @@ -226,7 +243,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD if (event.getAction() == MotionEvent.ACTION_UP) { imagePressed = false; playSoundEffect(SoundEffectConstants.CLICK); - didPressedImage(); + didClickedImage(); invalidate(); } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { imagePressed = false; @@ -260,6 +277,14 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD } } } + } else if (listenForUnpressed) { + if (event.getAction() == MotionEvent.ACTION_POINTER_UP || event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + if (listenForUnpressed && mediaDelegate != null) { + mediaDelegate.didUnpressedImage(this); + } + listenForUnpressed = false; + } + result = true; } } if (!result) { @@ -269,11 +294,11 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD return result; } - private void didPressedImage() { + private void didClickedImage() { if (currentMessageObject.type == 1) { if (buttonState == -1) { if (mediaDelegate != null) { - mediaDelegate.didPressedImage(this); + mediaDelegate.didClickedImage(this); } } else if (buttonState == 0) { didPressedButton(); @@ -294,12 +319,12 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD } } else if (currentMessageObject.type == 4) { if (mediaDelegate != null) { - mediaDelegate.didPressedImage(this); + mediaDelegate.didClickedImage(this); } } else if (currentMessageObject.type == 9) { if (buttonState == -1) { if (mediaDelegate != null) { - mediaDelegate.didPressedImage(this); + mediaDelegate.didClickedImage(this); } } } @@ -358,7 +383,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD } } else if (buttonState == 3) { if (mediaDelegate != null) { - mediaDelegate.didPressedImage(this); + mediaDelegate.didClickedImage(this); } } } @@ -467,6 +492,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD currentNameString = null; infoLayout = null; nameLayout = null; + updateSecretTimeText(); } if (messageObject.type == 9) { @@ -589,6 +615,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD photoImage.setImageBitmap(messageObject.isOut() ? placeholderOutDrawable : placeholderInDrawable); } } + photoImage.setForcePreview(messageObject.isSecretMedia()); invalidate(); } @@ -754,6 +781,25 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD buttonX = (int)(x + (photoWidth - size) / 2.0f); buttonY = (int)(AndroidUtilities.dp(7) + (photoHeight - size) / 2.0f); progressRect.set(buttonX + AndroidUtilities.dp(1), buttonY + AndroidUtilities.dp(1), buttonX + AndroidUtilities.dp(47), buttonY + AndroidUtilities.dp(47)); + deleteProgressRect.set(buttonX + AndroidUtilities.dp(3), buttonY + AndroidUtilities.dp(3), buttonX + AndroidUtilities.dp(45), buttonY + AndroidUtilities.dp(45)); + } + + private void updateSecretTimeText() { + if (currentMessageObject == null) { + return; + } + String str = currentMessageObject.getSecretTimeString(); + if (str == null) { + return; + } + if (currentInfoString == null || !currentInfoString.equals(str)) { + currentInfoString = str; + infoOffset = 0; + infoWidth = (int)Math.ceil(infoPaint.measureText(currentInfoString)); + CharSequence str2 = TextUtils.ellipsize(currentInfoString, infoPaint, infoWidth, TextUtils.TruncateAt.END); + infoLayout = new StaticLayout(str2, infoPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + invalidate(); + } } @Override @@ -826,6 +872,29 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD currentButtonDrawable.draw(canvas); } + if (buttonState == -1 && currentMessageObject.isSecretMedia()) { + int drawable = 5; + if (currentMessageObject.messageOwner.destroyTime != 0) { + if (currentMessageObject.isOut()) { + drawable = 7; + } else { + drawable = 6; + } + } + setDrawableBounds(buttonStatesDrawables[drawable], buttonX, buttonY); + buttonStatesDrawables[drawable].draw(canvas); + if (!currentMessageObject.isOut() && currentMessageObject.messageOwner.destroyTime != 0) { + long msTime = System.currentTimeMillis() + ConnectionsManager.getInstance().getTimeDifference() * 1000; + float progress = Math.max(0, (long)currentMessageObject.messageOwner.destroyTime * 1000 - msTime) / (currentMessageObject.messageOwner.ttl * 1000.0f); + canvas.drawArc(deleteProgressRect, -90, -360 * progress, true, deleteProgressPaint); + if (progress != 0) { + int offset = AndroidUtilities.dp(2); + invalidate((int)deleteProgressRect.left - offset, (int)deleteProgressRect.top - offset, (int)deleteProgressRect.right + offset * 2, (int)deleteProgressRect.bottom + offset * 2); + } + updateSecretTimeText(); + } + } + if (progressVisible) { canvas.drawArc(progressRect, -90 + radOffset, Math.max(4, 360 * animatedProgressValue), false, progressPaint); } @@ -842,7 +911,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD infoLayout.draw(canvas); canvas.restore(); } - } else if (infoLayout != null && (buttonState == 1 || buttonState == 0 || buttonState == 3)) { + } else if (infoLayout != null && (buttonState == 1 || buttonState == 0 || buttonState == 3 || currentMessageObject.isSecretMedia())) { infoPaint.setColor(0xffffffff); setDrawableBounds(mediaBackgroundDrawable, photoImage.getImageX() + AndroidUtilities.dp(4), photoImage.getImageY() + AndroidUtilities.dp(4), infoWidth + AndroidUtilities.dp(8) + infoOffset, AndroidUtilities.dpf(16.5f)); mediaBackgroundDrawable.draw(canvas); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 23a55f33..151f2b02 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -117,7 +117,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private TypingDotsDrawable typingDotsDrawable; private View emptyViewContainer; private ArrayList actionModeViews = new ArrayList(); - private Semaphore testSemaphore = new Semaphore(0); private TextView bottomOverlayText; @@ -175,6 +174,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private String startVideoEdit = null; + private Runnable openSecretPhotoRunnable = null; + private final static int copy = 1; private final static int forward = 2; private final static int delete = 3; @@ -354,12 +355,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not loading = true; - MessagesController.getInstance().loadMessages(dialog_id, AndroidUtilities.isTablet() ? 30 : 20, 0, true, 0, classGuid, true, false, testSemaphore); - try { - testSemaphore.acquire(); - } catch (Exception e) { - FileLog.e("tmessages", e); - } + MessagesController.getInstance().loadMessages(dialog_id, AndroidUtilities.isTablet() ? 30 : 20, 0, true, 0, classGuid, true, false, null); if (currentUser != null) { userBlocked = MessagesController.getInstance().blockedUsers.contains(currentUser.id); @@ -2143,7 +2139,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (!obj.isOut() && obj.isUnread()) { if (!paused) { - obj.messageOwner.unread = false; + obj.setIsRead(); } markAsRead = true; } @@ -2217,7 +2213,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not for (Integer ids : markAsReadMessages) { MessageObject obj = messagesDict.get(ids); if (obj != null) { - obj.messageOwner.unread = false; + obj.setIsRead(); updated = true; } } @@ -2322,11 +2318,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not for (MessageObject obj : messages) { if (!obj.isOut()) { continue; - } else if (obj.isOut() && !obj.messageOwner.unread) { + } else if (obj.isOut() && !obj.isUnread()) { break; } if (obj.messageOwner.date <= date) { - obj.messageOwner.unread = false; + obj.setIsRead(); } } updateVisibleRows(); @@ -2539,7 +2535,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not break; } if (!messageObject.isOut()) { - messageObject.messageOwner.unread = false; + messageObject.setIsRead(); } } readWhenResume = false; @@ -3354,7 +3350,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return view; } } - MessageObject message = messages.get(messages.size() - i - offset); + final MessageObject message = messages.get(messages.size() - i - offset); int type = message.contentType; if (view == null) { LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); @@ -3427,7 +3423,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (view instanceof ChatMediaCell) { ((ChatMediaCell)view).mediaDelegate = new ChatMediaCell.ChatMediaCellDelegate() { @Override - public void didPressedImage(ChatMediaCell cell) { + public void didClickedImage(ChatMediaCell cell) { MessageObject message = cell.getMessageObject(); if (message.isSendError()) { createMenu(cell, false); @@ -3509,6 +3505,43 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not public void didPressedOther(ChatMediaCell cell) { createMenu(cell, true); } + + @Override + public boolean didPressedImage(final ChatMediaCell cell) { + final MessageObject messageObject = cell.getMessageObject(); + if (messageObject == null || !messageObject.isSecretMedia()) { + return false; + } + openSecretPhotoRunnable = new Runnable() { + @Override + public void run() { + if (openSecretPhotoRunnable == null) { + return; + } + chatListView.requestDisallowInterceptTouchEvent(true); + openSecretPhotoRunnable = null; + if (!messageObject.isOut() && messageObject.messageOwner.destroyTime == 0) { + MessagesController.getInstance().markMessageAsRead(dialog_id, message.messageOwner.random_id); + messageObject.messageOwner.destroyTime = messageObject.messageOwner.ttl + ConnectionsManager.getInstance().getCurrentTime(); + cell.invalidate(); + } + SecretPhotoViewer.getInstance().setParentActivity(getParentActivity()); + SecretPhotoViewer.getInstance().openPhoto(messageObject); + } + }; + AndroidUtilities.RunOnUIThread(openSecretPhotoRunnable, 100); + return true; + } + + @Override + public void didUnpressedImage(ChatMediaCell cell) { + if (openSecretPhotoRunnable != null) { + AndroidUtilities.CancelRunOnUIThread(openSecretPhotoRunnable); + openSecretPhotoRunnable = null; + } else { + SecretPhotoViewer.getInstance().closePhoto(); + } + } }; } @@ -3693,7 +3726,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not checkImage.setVisibility(View.INVISIBLE); } } else if (message.isSent()) { - if (!message.messageOwner.unread) { + if (!message.isUnread()) { halfCheckImage.setVisibility(View.VISIBLE); checkImage.setVisibility(View.VISIBLE); halfCheckImage.setImageResource(R.drawable.msg_halfcheck); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index f42452d5..c1470125 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -836,6 +836,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa @Override protected void onDestroy() { PhotoViewer.getInstance().destroyPhotoViewer(); + SecretPhotoViewer.getInstance().destroyPhotoViewer(); super.onDestroy(); onFinish(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SecretPhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/SecretPhotoViewer.java new file mode 100644 index 00000000..b7e585ff --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/SecretPhotoViewer.java @@ -0,0 +1,279 @@ +/* + * This is the source code of Telegram for Android v. 1.7.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2014. + */ + +package org.telegram.ui; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.RectF; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.WindowManager; +import android.widget.FrameLayout; + +import org.telegram.android.AndroidUtilities; +import org.telegram.android.ImageReceiver; +import org.telegram.android.MessageObject; +import org.telegram.android.NotificationCenter; +import org.telegram.messenger.ConnectionsManager; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.TLRPC; + +import java.util.ArrayList; + +public class SecretPhotoViewer implements NotificationCenter.NotificationCenterDelegate { + + private class FrameLayoutDrawer extends FrameLayout { + public FrameLayoutDrawer(Context context) { + super(context); + setWillNotDraw(false); + } + + @Override + protected void onDraw(Canvas canvas) { + getInstance().onDraw(canvas); + } + } + + private class SecretDeleteTimer extends FrameLayout { + private String currentInfoString; + private int infoWidth; + private TextPaint infoPaint = null; + private StaticLayout infoLayout = null; + private Paint deleteProgressPaint; + private RectF deleteProgressRect = new RectF(); + + public SecretDeleteTimer(Context context) { + super(context); + setWillNotDraw(false); + + infoPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + infoPaint.setTextSize(AndroidUtilities.dp(15)); + infoPaint.setColor(0xffffffff); + + deleteProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + deleteProgressPaint.setColor(0xffe6e6e6); + } + + private void updateSecretTimeText() { + if (currentMessageObject == null) { + return; + } + String str = currentMessageObject.getSecretTimeString(); + if (str == null) { + return; + } + if (currentInfoString == null || !currentInfoString.equals(str)) { + currentInfoString = str; + infoWidth = (int)Math.ceil(infoPaint.measureText(currentInfoString)); + CharSequence str2 = TextUtils.ellipsize(currentInfoString, infoPaint, infoWidth, TextUtils.TruncateAt.END); + infoLayout = new StaticLayout(str2, infoPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + invalidate(); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + deleteProgressRect.set(getMeasuredWidth() - AndroidUtilities.dp(27), 0, getMeasuredWidth(), AndroidUtilities.dp(27)); + } + + @Override + protected void onDraw(Canvas canvas) { + if (currentMessageObject == null) { + return; + } + long msTime = System.currentTimeMillis() + ConnectionsManager.getInstance().getTimeDifference() * 1000; + float progress = Math.max(0, (long)currentMessageObject.messageOwner.destroyTime * 1000 - msTime) / (currentMessageObject.messageOwner.ttl * 1000.0f); + canvas.drawArc(deleteProgressRect, -90, -360 * progress, true, deleteProgressPaint); + if (progress != 0) { + int offset = AndroidUtilities.dp(2); + invalidate((int)deleteProgressRect.left - offset, (int)deleteProgressRect.top - offset, (int)deleteProgressRect.right + offset * 2, (int)deleteProgressRect.bottom + offset * 2); + } + updateSecretTimeText(); + + if (infoLayout != null) { + canvas.save(); + canvas.translate(getMeasuredWidth() - AndroidUtilities.dp(34) - infoWidth, AndroidUtilities.dp(5)); + infoLayout.draw(canvas); + canvas.restore(); + } + } + } + + private Activity parentActivity; + private WindowManager.LayoutParams windowLayoutParams; + private FrameLayout windowView; + private FrameLayoutDrawer containerView; + private ImageReceiver centerImage = new ImageReceiver(); + private SecretDeleteTimer secretDeleteTimer; + + private MessageObject currentMessageObject = null; + + private static volatile SecretPhotoViewer Instance = null; + public static SecretPhotoViewer getInstance() { + SecretPhotoViewer localInstance = Instance; + if (localInstance == null) { + synchronized (PhotoViewer.class) { + localInstance = Instance; + if (localInstance == null) { + Instance = localInstance = new SecretPhotoViewer(); + } + } + } + return localInstance; + } + + @SuppressWarnings("unchecked") + @Override + public void didReceivedNotification(int id, Object... args) { + if (id == NotificationCenter.messagesDeleted) { + if (currentMessageObject == null) { + return; + } + ArrayList markAsDeletedMessages = (ArrayList)args[0]; + if (markAsDeletedMessages.contains(currentMessageObject.messageOwner.id)) { + closePhoto(); + } + } + } + + public void setParentActivity(Activity activity) { + if (parentActivity == activity) { + return; + } + parentActivity = activity; + + windowView = new FrameLayout(activity); + windowView.setBackgroundColor(0xff000000); + windowView.setFocusable(false); + + containerView = new FrameLayoutDrawer(activity); + containerView.setFocusable(false); + windowView.addView(containerView); + FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams)containerView.getLayoutParams(); + layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT; + layoutParams.height = FrameLayout.LayoutParams.MATCH_PARENT; + layoutParams.gravity = Gravity.TOP | Gravity.LEFT; + containerView.setLayoutParams(layoutParams); + + secretDeleteTimer = new SecretDeleteTimer(activity); + containerView.addView(secretDeleteTimer); + layoutParams = (FrameLayout.LayoutParams)secretDeleteTimer.getLayoutParams(); + layoutParams.gravity = Gravity.TOP | Gravity.RIGHT; + layoutParams.width = AndroidUtilities.dp(100); + layoutParams.height = AndroidUtilities.dp(27); + layoutParams.rightMargin = AndroidUtilities.dp(19); + layoutParams.topMargin = AndroidUtilities.dp(19); + secretDeleteTimer.setLayoutParams(layoutParams); + + windowLayoutParams = new WindowManager.LayoutParams(); + windowLayoutParams.height = WindowManager.LayoutParams.MATCH_PARENT; + windowLayoutParams.format = PixelFormat.TRANSLUCENT; + windowLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; + windowLayoutParams.gravity = Gravity.TOP; + windowLayoutParams.type = WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; + windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + + centerImage.setParentView(containerView); + } + + public void openPhoto(MessageObject messageObject) { + if (parentActivity == null || messageObject == null || messageObject.messageOwner.media == null || messageObject.messageOwner.media.photo == null) { + return; + } + + NotificationCenter.getInstance().addObserver(this, NotificationCenter.messagesDeleted); + + TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(messageObject.messageOwner.media.photo.sizes, AndroidUtilities.getPhotoSize()); + int size = sizeFull.size; + if (size == 0) { + size = -1; + } + centerImage.setImage(sizeFull.location, null, null, size, false); + currentMessageObject = messageObject; + + AndroidUtilities.lockOrientation(parentActivity); + + try { + if (windowView.getParent() != null) { + WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE); + wm.removeView(windowView); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE); + wm.addView(windowView, windowLayoutParams); + secretDeleteTimer.invalidate(); + } + + public void closePhoto() { + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.messagesDeleted); + if (parentActivity == null) { + return; + } + currentMessageObject = null; + AndroidUtilities.unlockOrientation(parentActivity); + centerImage.setImageBitmap((Bitmap)null); + try { + if (windowView.getParent() != null) { + WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE); + wm.removeView(windowView); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public void destroyPhotoViewer() { + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.messagesDeleted); + if (parentActivity == null || windowView == null) { + return; + } + try { + if (windowView.getParent() != null) { + WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE); + wm.removeViewImmediate(windowView); + } + windowView = null; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + Instance = null; + } + + private void onDraw(Canvas canvas) { + canvas.save(); + canvas.translate(containerView.getWidth() / 2, containerView.getHeight() / 2); + Bitmap bitmap = centerImage.getBitmap(); + if (bitmap != null) { + int bitmapWidth = bitmap.getWidth(); + int bitmapHeight = bitmap.getHeight(); + + float scaleX = (float) containerView.getWidth() / (float) bitmapWidth; + float scaleY = (float) containerView.getHeight() / (float) bitmapHeight; + float scale = scaleX > scaleY ? scaleY : scaleX; + int width = (int) (bitmapWidth * scale); + int height = (int) (bitmapHeight * scale); + + centerImage.setImageCoords(-width / 2, -height / 2, width, height); + centerImage.draw(canvas, -width / 2, -height / 2, width, height); + } + canvas.restore(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java index 718fb101..31bf865d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java @@ -318,7 +318,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen return fragmentView; } - public void didReceivedNotification(int id, Object... args) { + public void didReceivedNotification(int id, final Object... args) { if (id == NotificationCenter.updateInterfaces) { int mask = (Integer)args[0]; if ((mask & MessagesController.UPDATE_MASK_AVATAR) != 0 || (mask & MessagesController.UPDATE_MASK_NAME) != 0) { @@ -338,11 +338,16 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen } } else if (id == NotificationCenter.encryptedChatCreated) { if (creatingChat) { - NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); - TLRPC.EncryptedChat encryptedChat = (TLRPC.EncryptedChat)args[0]; - Bundle args2 = new Bundle(); - args2.putInt("enc_id", encryptedChat.id); - presentFragment(new ChatActivity(args2), true); + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); + TLRPC.EncryptedChat encryptedChat = (TLRPC.EncryptedChat)args[0]; + Bundle args2 = new Bundle(); + args2.putInt("enc_id", encryptedChat.id); + presentFragment(new ChatActivity(args2), true); + } + }); } } else if (id == NotificationCenter.encryptedChatUpdated) { TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat)args[0]; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/VideoEditorActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/VideoEditorActivity.java index 01072920..1de73843 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/VideoEditorActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/VideoEditorActivity.java @@ -276,22 +276,27 @@ public class VideoEditorActivity extends BaseFragment implements TextureView.Sur }); if (Build.VERSION.SDK_INT < 18) { - MediaCodecInfo codecInfo = MediaController.selectCodec(MediaController.MIME_TYPE); - if (codecInfo == null) { - compressVideo.setVisibility(View.GONE); - } else { - String name = codecInfo.getName(); - if (name.equals("OMX.google.h264.encoder") || - name.equals("OMX.ST.VFM.H264Enc") || - name.equals("OMX.Exynos.avc.enc") || - name.equals("OMX.MARVELL.VIDEO.HW.CODA7542ENCODER") || - name.equals("OMX.MARVELL.VIDEO.H264ENCODER")) { + try { + MediaCodecInfo codecInfo = MediaController.selectCodec(MediaController.MIME_TYPE); + if (codecInfo == null) { compressVideo.setVisibility(View.GONE); } else { - if (MediaController.selectColorFormat(codecInfo, MediaController.MIME_TYPE) == 0) { + String name = codecInfo.getName(); + if (name.equals("OMX.google.h264.encoder") || + name.equals("OMX.ST.VFM.H264Enc") || + name.equals("OMX.Exynos.avc.enc") || + name.equals("OMX.MARVELL.VIDEO.HW.CODA7542ENCODER") || + name.equals("OMX.MARVELL.VIDEO.H264ENCODER")) { compressVideo.setVisibility(View.GONE); + } else { + if (MediaController.selectColorFormat(codecInfo, MediaController.MIME_TYPE) == 0) { + compressVideo.setVisibility(View.GONE); + } } } + } catch (Exception e) { + compressVideo.setVisibility(View.GONE); + FileLog.e("tmessages", e); } } diff --git a/TMessagesProj/src/main/res/drawable-hdpi/burn.png b/TMessagesProj/src/main/res/drawable-hdpi/burn.png index 25833185e6aa7115b8dff49baa16aa146981210e..9caed35ecd288cdda90455b02d1a469ac585b586 100755 GIT binary patch delta 2359 zcmZ{mdpOgJAIHCDtGQLkbzwA7w6HZv#ExxPBtx!YNO*QkbK9&o*Cb`9+`2Hy!V%g* zbH+MS%WdQ!a!bkWhmcE&96#rIe!oBa%rlvSF7H?tl3mStmvp|{S zF&La4Jf1>zayn@j85Bba`8C?X&Ps1*gA5J}KKVZ_`e)iZ#UPXa8<_s=NDoenb`80B zGWh2PW}=iQhvpwdoN*)UZ&^fsXa?D8%htA%Qj*eK->3Gd z=WLYezId8qcqG+s3x54-x7$tAt6y%|>Fa)xPEp^F)1x>f+9{};xNyi2w-nGHZUKrM zLQ_cKU}17iTg;%}0*ICeIlH{KLqyYA>5$w-(L(V}OA#zAN3K<40(=>4!G2;hXQOxf zSJ@Ka3RodI%_bSHQKo}#@I6-ITE1GSwgiaxOzd6WMQ0o5#hdkM9=CLuc zhv)-x&;k!*ZlsE~_JXd`^?nr<6`nozTx!f^d)+oU~ zH8u4=<>loIcyKV!DeAGUt;nZf$*c85wmXd|S{;>35c(5dO#Ex?^wW-tmL}PAiF{ zQa$~>y^nm<;8?n$P${1r@5Nu3@8J=pe2II9nM~%X_KptLxZ*yuD3Zp|W~d9= znwVt(fj|Zw5x3QmVFpc)OH1pV?Vi@v)wQ*?4Yny4tzng<&j}fQg;CfgL2#cG&d%Fz??;5S`JkEnu|_(o%{un`@?_r2moIhD)#lQ2^711#FwTSi zQ2}L`^-K}x~8`W~W-Zi`V;YBjWW8@JKT3C}G%3diff|mK) z15Um52|KZD&(F^{9`=3o=uwbZEEc7W$UWfeUsdfn^}esKk5BqN!1lkpmS@jG1vg(SYr|2u#sAV}9)^KUY^)&*Ds+=SvMeK&^RgqvCw^>kop2uY5T*WcIn}E-ROI z!XSGp99&r{ivL1pF1{DhXA=5a5K0clc^@;B4V>dY57tcA@VQ3ktM*S%PC6V0g$KuZ zyiKzmMpPPLpP)eQ`Y@q94X5Ufpe>!RkW%pbJr zuH&Q>l!K?_?$kh^4*x~bsn^XVJRbeQY1Y-!yu3WvuJj=?{D7+{X0HF(It-iYmHw2= zd;HiVY4L9H560OdhSj<4psFaPYbsAqkO~fF-@iZX=jG+axqJ7!sOq6!CbwHrAQ1eO zO#SHY;o-6SmoaMPpg(I~dgyrzA#weOjo|jYZg!z&rxXfLJbb&-_Jmny&m*~g`1+9A z@nV(m`~fpVs~TV6Vc@r-Kn1CA;Kb;V^9<}vOSR160Px@&qB`>-`>FYj4)w_j^*vLS z`yAh_l7WW`O7`vUP=dpUnS#U3lL;!w3gpGysJ}8*0`l|5@*%9;Od6zQAuYS=cCHg{ zxu;qGOCC;?otyfJY5Uvt7cZ=R6=!M|BWf|KR6Wj_u%N`vlD`Ajft0Ty5wf?whR~Gv zJbtged*Gf%f}+VTmb*lDNc$RPcFiL&GYaF$z&9}`e0Se$#Hm%?8+_G0T0D0&?3ok! z29lE2OQQaMpz4YvH8j_{LZ{&9o_B&fKtIBq-aB34YaieA{*cR=@gs7o;7lJXP#|)G kV+OW52F-n;-P<5}K#|@M5citI+WCb52b{BA6*eI0zi`w(j{pDw delta 2196 zcmZ{mc{J1w7sm%fmc*D!$vP%WPsA9zsbOXq$-X2JF_vtNv1IKxmKgh*T|=W`kR_fW zjHOU{Wyz8!dqR|*Qi{iW&inq^ANSsKzUO|<_n+@Q=T-<)PD{m`nHcc%itvI!AbvwU z*5YXD{kOQej{3Y6=yRRad3Jjh1QMx-L8v1&H8qr#aYzj%ePvx;H4SB)suDsUp$d}> z_8}S@YhmxY1p2u81{h*dup>p0aEGAvKUU*UZ02KjrT-hK{%Hv&=^tR>>ZV2bvw_;5 z*i1zZJwR;f6dVLP7H){uwF>_5$^OnYtLrE4D|tWTw@kDYG`ism%~H5ZQH?yk8TZaf zPYZV(soW&<+r>F4elzZh{bM~Sluxk)%-JY$GKylvTM{MTYsZ_x&3m)oM!OA+S^JI8&(BYB&y$U`z4(^uiulJj1g*}r&)5=Th^^hymm%prwpNBtAGtE+qEs!8uWz3b)G^0=WPppnHweVG&KkbRM;3b|fw zAK%&3nYON>tz8rTYtIknGTLf|#cKo^tq%*GI<)|EFIRCt$${SZIaD@Skg~sH{9!P*4zema*4U7#JJx2VjWA+I78&H@&^in%L5c z=Q~C=?Pm7&7yXa)_tvH*X2+38WJ7avGp|X(cr1-J-@yv|-h8H9)4TuO711mAbq2e; zaW!Ax_4M>;>FBf;S5R^vv`It{A$_2OadiMc-<6R*r^yS%duLoFL6;cM*lkJFz z2o4Me6YP@nmz-SiO>^_jYvtl6RJrCFRWq}~jshVhAdspW8(vmlzb$sC0>AYnGcz-4 zUy^{xyX5-tA-?O353GY5@Ol3Vopp5q-d;tg)1!gIvo5h)Tcplgb4yDGVZDcBYU0KM^&OV)GZ6gU;_kc!vrR7%_T>;vz?zWYc9lJN+Cu>qzK5Ero zS!pCy8;sE|U%|OC;;IIV42lX17qL}SQ&X&aYm>_#eJt*x1s*wd&Y5)#zh`G3%I zm6OTXR=P3v?%f)8Qmkf4psVXbl@AJs18}Hu<%Yk{Bahcc^j>K1QJgfLFdZ2k4di~< z9=!SZ{UB44oIf92ke}~y5R$-PFz%1q`aUu2Vpx`eiyQ%n^E3T3VbQrg^X2Z2H}N5{t0 z<|mKtJA-(W%v@g`ufv4yZ2)s%RcBwSrawK;?J>@KaU{MYFPaX`mwGuotfH;1-snvr z5Jvj@`D(gCa@Kvn6S6XEV%b^1&la zw;NqB6$k7xOwBJ=C~`@xdN@Tx*l-$pvu6nd=8b*b)DkfgV`#QInB(Pe?H#S8kt~|h z`GF20#H4N5T*m>J?A8rBukR1x0&X5&y{NGV)PXs<;XsF%x23SfwrQVLNIa(LIMMl+ zKH)#UrfP3-UN2-4CBCa&T4WoSg?r!1;;0S3(I-80YLb2JZLJnOwg2S30ZtWBgwfBm z*1?7(ZM$gDv}n;QnFi2`CN#u5O2!<8=O}YHh(=b$Q_W>bRPj<}eLCwNK?Ky diff --git a/TMessagesProj/src/main/res/drawable-hdpi/circle.png b/TMessagesProj/src/main/res/drawable-hdpi/circle.png new file mode 100755 index 0000000000000000000000000000000000000000..fb0b2f899dc605481fc84e5dbedeca331d2c3461 GIT binary patch literal 1874 zcmaJ?X;c$u6rB)JQBW)xQKF7`wYMdCR*?^I300^03#x&YYgaA{JG`&&8czUFf0qS)k#%!L9 zEyKc)bbVB=35m;%QE78CwE`Vu#&j^mEF=XC2%!PZhAbm4G>aJTb%o^Ixy@pL?;%8{ zi18sQwM-6%p(X_6F@plNYzPARd?v)@@%c~y$YDbq7Mr~Jfe=^7;|n=c!H*Y%jAqiM z3YBog$5`Y_#7HLyOvqy8@Ga;^`;`hQ;wgzu9`D4$Z+Q zzsJjDLa7laG)65Vg+&ZffvMN)gd8Y{4+&raH$uXLpm44v9Oi|E28D7ZywGVu0)8(S zMzz@n#7OjVb)UJCKDkaS7%(z2jF|Kb5M6``HGuC+7V7)XWon;#AGx}|bD7pBmqjMS zayIr~jqcqd-Q%2ovMsszWPHR(y4^(Dde;i0l>Ay+q_9L~zW%7 z42-y3Wt+!_{EB@O_BNeZ2EX)eg1xo|B%ST=SqfPr7E#K(JoEcmE_1#v+FYUy4vN;N zUEe5}+hs_n-kkfS;la&dJSNoDpZa9U5qr!*sqJ{s(xhn(BDdk?^4ZwRj6a#>l2%7UsEi2&iyI~^VeHp9NJ<9ZTnfQj~D zW_IQIcdCW#kfAe*aEXhxjWZ-?CzkH9xjmsHxU$6YcFMBO%J4&1CcHTrE56pgu)O5XY*ydZq zd+5-^15_@UwKBWGN4^OktB^FPQ}zCpM>lkclDn+_Uy9ckNS8D9;=%yd>wC2C5~xjr zbK{a#x#hO4b0>MWbql6*Frig>B`K!Q3d(<1TXQE42IZZ zZx3*(WBJgt#d$-Po#ICR+m$=Vg#k^YM@UvMjY?F?Sw|7J+Bq#3X4{xQ_Gm=*BU)r%BafNdOlV&EU zDS^it3(gPAcMTSMUrjAowW+!5Y#T-Co<6k&OMet}b*wkly5?<(4|P+^qc)tnEzOoe zzc}aQzEf_V@h75B2C%HPF`5_jTncR6+xgOmvS~oY#3Ms*-mcrhY3cSkmhhl;ArZf!|j| z+fLc=Vx;QDxUEyZsoug*%xyh%+AYhky#CPRcu~a|^^JZ%W6A64#Fh00%+?x%%jBfA hY70Nat#vM?KQQ1AkLaz1@CD~zP8uEq?+Kl^^dFe<+j{^2 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/photocheck.png b/TMessagesProj/src/main/res/drawable-hdpi/photocheck.png new file mode 100755 index 0000000000000000000000000000000000000000..a2aa287f56e7cbac20768530eed3ca9d865b7394 GIT binary patch literal 2401 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 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-ldpi/burn.png b/TMessagesProj/src/main/res/drawable-ldpi/burn.png index 8b6523488b99947552a1f9f0a93661e98354c224..9486b66ff9aac39b66e1c42d86383ebe260cf22c 100755 GIT binary patch delta 1286 zcmeC?Yvfn#4DfU3<&xrJU|`_&^l%9R(kdX#!3HEBGR&BJpz{JhO z*wE0`#KPI!!qv^m(Amw|z|z#&TuGrKx4_re$|XO!G&eP`#M8xA2`HkMl9^%!)oX}L z@8m^H22cykU2!Q=QYbD7N=>s$!D)fH8!o+*^_ZRNE%&~d$H2h+)zif>q~g|@h**!w zffE0|{S4l@Ogbyo%6EB_-{CDS9U96D-#R(BtZZ~H)2vWjR32BU9;eZAp;hr`acYw| zUt5?kTjr@58%rKuyRfrFx5VD+|FXUA=hTaRf1fi;=eN22^W5=sm1XCu?|t5<->%fo zpux0^d2%D?fqLy9cl9nX{$Y(_lWLTH&RbSeQu1o%;UE@X5oYhkOqTu5nH9c(`s z$TV$g2uctVm3niaaDiro<3$I~4J};y&lcJfHsk`{%CMHK|EsmgOxD)*G*d6z%Qj&z?QIn!PYL_w3zk*OqY~oHya|-&1QY zG$*)aW@Ma5ytQ`iT77G4>u#rrr9o+@FWgn(No!fPYE|{V^SZjaQ{TRQ`}3fbMb2ym zE~(Z7F_+@a&CS!VU%6uQt^U2fwzlwWAGODS{_L4t;E{5C|3!Dv4|*#VW`s+1p%>Hd=Yn$6Jd3s@vKxU@7u2^^E>Z?{9EUuUB4vOBczq<4M z^UuOeNA0d&y(;f`#DAId!T^zOmqpnuhmT)UNqY6_RnXF)Oo!^tx8Lf0xqJEY=gybf z8X5v8pMKJrWSJpTw#liovT|2|h7G4@kK5xI(}CTQk+w)QUJ+fCf+4 z%yee=^WQdBR==2eZeF}`!y?CQcKM8dU%!48cK%jj^P8n9$K)JeL}FQ4+0~~-I|HkW zi!ZMXTG{vCCqDlEO2eR_pdT-)tE+D_FVC6kaDhu`OUvfwdZu-(e~%nFvhl2otLw#r zPyemzMNE8ylQvoiZ@rqeb=~5{&i)e?>RhzQk5b&R-%dwIN8(_@`tRSq*?p0^j;0Mzt$=lf+boPF6QfO=POu zTYs%lCc?JVvV#3~>X-hNfo?1JvKU6W`7BtIEc5))#3t7Bm1$Bfb8Z-{v~8WB!FTx8 zo6WvU;~DegCrD@)Ovu%GJNxLqAMsth`ve}&(Uo~Bp{kb@8+EYj&~}Fi?yyF$s+&8O qOfPZsJm07PR`t>($$RpQYz*-^`Les(^DY64HU>{uKbLh*2~7Z9iz$i# delta 1167 zcmZqV@8(nN4DfU3<&xrJU|`_&^l%9R(uyF=!3HG5pB&2HsHn;mW9;N+XlUf>tRop9-$ zyokvFW`PARMM?_AB|)iaRw=kGu*9WzvL3Tjz5Cx7b_NFKdQTU}kcwMpBJO)f1yEglnWenBR}9#fa=KdvOy`9i5h z;^VGJ!MQc|hZinfcxLjI>(}q!zI#{K&4V}2Tzk>%_sL(re@~B(O-^2X>G|iG-8Xvk z!dkkPt1nr$e7Us*L;0GOD_0(TTQ<9*Yr;j7wN6S`YM%D@_P+ewyM5a>yE*gczkh5w zch+6bq#JL`Vnahki?9AYSby-~a%E-Znr9&k4}Xz~a8Fqq6w1QXIDJFw^kd=S;dcxC z7lvqw&OA|CA~N}8%6bmhBNzM(mP|@dOPlwU%b~zRW;R>%!DDgWOE2yE`0=CIp-f4} zK2g?%SF=>B_QuVAKhJ65iWcXYH*Vbcuqjz>^2+7_m(~VppMR{~M;B=_Z@B)jzTk&} zSohJu`pittj$0>BdWs)kti|cNWI~6^MZvJuPw%|Gc=2NYgKdEo%VPAzy%JWmwzd}7 z$l0HKV|X}3sLNy8!zpVX9BlDDacpKh!xjZA`ReNG!gY5K9&}u?ZCjYrb8DNQf{w!M zo;rW){wv#TVAA&9$=o=c%F8;qt>%XZf;aX6G4K%=b_^ z_vz+|r=N;CRKEw-7Zw)w2DHq-+nJ&0z5e>_Em3Rb1LBuoEI{l@mmx`)Dbd-m>qo1dRw z@4SOs`%b;auD;EWnr6(Md-wg@x3#=+m$>5skMse9zB||Kws?p9`$ZRDuqKN2UE4e5 zMOMMT@@NOn_kMYcb~j)Cbo+qRcD|FoC36q_72@W2@ayrZoZtK(Y}fI7F`BHm-OlhU zUwcE)l|}O#=e-Vl+FuZ)^)zy-vi*mzyFx1${ukys=N@DsrL;If;?bY^9+Usf|Dk<= Zp{7vz-et3zHeeaU;OXk;vd$@?2>_ka2|xe< diff --git a/TMessagesProj/src/main/res/drawable-ldpi/circle.png b/TMessagesProj/src/main/res/drawable-ldpi/circle.png new file mode 100755 index 0000000000000000000000000000000000000000..d1e03ff934c4ef9d87984934a21ccf0fd31f6bbc GIT binary patch literal 1354 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBBuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFe_z-M3hAM`dB6B=jtVb)aX^@765fKFxc2v6eK2Rr0UTq__OB&@Hb09I0xZL0)vRD^GUf^&XRs)DJWv2L<~p`n7AnVzAE zshOFfj)IYap^?4;5Si&3npl~dSs9rtK!Fm_wxX0Ys~{IQs9ivwtx`rwNr9EVetCJh zUb(Seeo?xx^|#0uTKVr7^KE~&-IMVSR9nfZANAQKal@=Hr> zm4GgVcpgi&u1T;Y}Gc(1?$ko}^&B?;R#Ldyv(9qSy$<^G@)xyHi+|a<- z%+bsVrq?AuximL5uLPzy1)eUB2MjsThND&Pa0;V1i6P|2=9C*S{%>$`GjQmeYAFxi~QO~>5yntO*aYliF z&ujaWQ?Bq%67#mM|0K)N_;=Ipx9@tEE;`PZ8o**%!13+JZhZq*`3I~P37g)Xw>kg& z>rF1rg$E^9G}g4-znGzXfwlI*F~txj-U*@qPfKh$_<5O=^#VSv1?mgKW`28dZzM4(<5WmPbWRq_p??rYf4VK z(6G9Bi!&ed+0x4a4Hr1B-|YNi>G# TwU2D$L8Y6gtDnm{r-UW|*s|aF literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-ldpi/photocheck.png b/TMessagesProj/src/main/res/drawable-ldpi/photocheck.png new file mode 100755 index 0000000000000000000000000000000000000000..66c4717200626f3f3b3560302c3e3a1c8cdf2850 GIT binary patch literal 1668 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBBuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFe_z-M3hAM`dB6B=jtVb)aX^@765fKFxc2v6eK2Rr0UTq__OB&@Hb09I0xZL0)vRD^GUf^&XRs)DJWv2L<~p`n7AnVzAE zshOFfj)IYap^?4;5Si&3npl~dSs9rtK!Fm_wxX0Ys~{IQs9ivwtx`rwNr9EVetCJh zUb(Seeo?xx^|#0uTKVr7^KE~&-IMVSR9nfZANAQKal@=Hr> zm4GgVcpgi&u1T;Y}Gc(1?$-v3X&C=A^#Ldyv(9qSy(#+i0)zs9@(8AHo z(8R(Jrq?AuximL5uLPzy1)4&F_V@SoV zGc$big&ZZ0mlt*icIH+JF0Sp|aLqYd+TfZ;g{RHe))p53)ZR`x+b_i*IQLANam~#4 z&BhuA=3HMN{%gWaoUxfbp^KMgL^J=jPs_OG%f0)6-oMHAEe41G%$Pa1a$fuMFRSIh z9dh2l{jT-==J$LL-hW8n!SeiJesA5Hu+@J*&%Dl&*y#Syv%~w$RrxlGArYld*Vw~d2 zX>!c(Zr;h0eD{PG?2h?v8p*zBcjko?6Yu10Hx=vNIXkyNC)%E|)9T%_X$hNduGz9_ z(w^geiRIIlQ37SnCYPjYsA(vt4=<7du7P0eQXk* zoWXk2`M>;8Y;2t?KAYFX-rl~HaZ}XVCKb>1S94|f+-1{tMCfc|VV0eD__Re%_LWsZ zD?>j2tTB}8?fY4?Z?>|s@>L+1B$QTM{F#NVdYP!iC2=OHW$IfZPrrTpc7B7_iiI3$ z$;r+_t{Y<|f*ccW9^5hQ+Ue7$Q}^sW5LY$FLq(3GDdFSqzvizD9v1A7mAJ%r_JaP8 zdDkw_O5>8=W?^k@ZDnYvc^_foVo~;_W*C=a&az*Fbm6E^HI5!tBF`YW? zK{ngL3yiy0m`)8#+Zg=cd!wVK{^^@mfqkBvmBOxbh1I`b?kB#+Py1!(nkCO|7BAU; iT<y0jsRqNM1$DkKjr0r5qeCSKQcEiH6c4Qew6pJApM*l1|0 zmR(CM^O@_TYd)c^FcTlEwWDE0`B-20*lIOPUGL1jfA+`uo|!Y}Gv7bHXXb3d|3+Af zgAV!_!gj*|05J6PWd(0{r~ejIZ(F|yf6QsLv;qI%*7Qud6S6F&R!%clSrhp z7(@n>w3qDcOtQiz@lFK<&{!vr3wSa7Gk&anR@)OtZXB2PKbG+&wonFk`o97BOG{SR z#52J$u{7?N4Jcn?3mtWsqCCK%0RVL4{aB2Uq!*Ln0sd$olOqk{I8dvzYn3%9dPk0l zlP-z?CNSpC`PQ=|C?-E;!`~__yUyRYJZMIF4=|@#hY%)JZ2jx7s?WRb5wdJ$7vY?< z3&8Xq`cCEN_g&nDI+VKP-}jDJ2d+cP#>UcLt4dd2bw=vr^0Gua&oa<}sfG~O!Ccp7 zpfWHSy1#;*3S0@&pi722X}}QZ7-W2YXOx~h*c}q4<3<1KiC!A?vbZJlK9iH-0i; zk@aug1C&=vmV{~Yly*~HoiFGDcGMWZOy1xw* zi`G^$1)fzy`TPQJE{j~%F ze`(qp?igB7bmK@F)Ut(DKT*VQ>hayXnyU+cTk*gi08_*Hd9#YCc0Vd5&)&F#3gvHt7+ zS7sPY`U%o*BU_79g`_-9Ao!r2oScLR)7{+M1|R&g|Fr&Au$_8nXju%kzj@}wF+z1s z&C?IN1l*>}3kwV8qY9%oZA#bXhNz&RV7}!!+#1fNeiAn}Hkx;huB@!|&d%C#!ot=x z%gaMbt-ZbdftbTZ(<|j66-XrVp+q9-#Ea(V=OfmHJf60yqa*c-x>zbL&wf4i6tmC6LoO{Y{&QzYXzhoa_4V4RORX&}4((`MabIL?T6FXSCPR^h z&oZJRUD{h)QT{Jyu1~#u`Ep*i@rg{)Bd%w8EMG7xmDu8j!haF2Vng zw-Xa0(Ww@lMxmkJL!nx&9!y9`5KVQ2g8tfb^Trztcj(S*qhVRmfjUUq;ANC$@R1%n zP3&dl8fN)XWF+)4_8CssSH<#CB0-lV9wXLCXHC$*_uHKAct=Z8c^Va{Ac4snS8U~~ zrR7Q2#;@{Y79to-4QTq@BCYddI&y6G1zB|8nDR~z+WhOxxo0^6&ECF{_3RxfkNJVb zC410?Tk7VdzoRHIJP(6u9}nZ-VEqd3fkCoJobo)-#k-$HK}k5vI{^-t|9ag TT)y4*O9A}64zlhtqcZ;i{^;MO delta 1542 zcmZ{kdo&XY9LHy4WremhuX*kEatPZL)5FF##x-x|F9(m*%@+#%JDUWg8bMF1KKYqX8IluG!obNf`^F6;6=++)xo+HIt0iq58 z000VP8-nxpH2Al6g15WY6)%~mx(9$hm}8cfW~L;J2^MRHLJ>`{CL}8?9*ss3(IiVW z7K7A@4h^@rHz%iBmn%z6-@owVPDe(Qh`w;$XI`)X6ZVS&8>bt1E;65Vih}+qgChaSTa8z%({+Sz;w5m1U z3==EF22GyU(7_~HOoD!>zupOhF4cMzLP{LdYFnP2HQrmA49Dl6d9~ zUnGZxbAg)AilFe^)F2%{8Pd7BY%`Aj0W$iF2}54WJ?$A05z#s{blcFvVhiaYb^{#Y zf#WZynPzrPONNKN>{+aeyN4K1p)#D>(l2s%bq&bh_^r5D4uiqCoxpdU&e>Pkyub1C z`KtN(`B9u_X+Qiuv+nHOf?9w*I%(R6Q}3PoYYvr4{hcvT(m&4?2n3=SK#ts|6c8>m zNdGiD>nMNK5+B@1DsrMwC<(7X7w`bpt6UGk28`%Lpwal|y~~}Qoep3yxI9v}2~vtg z$v`}P&O`?X+mtz%oJt=cmAH1YqoPLb?CdxbJ-bpLkz=j(+O7&;zuqGl<1ALl0r9OR zZxyKS?gOTP#WuvE2Z7%i7-em3tuVo8Yd1tz@_6#UT$^y#TcchMH0M*CeSLjZ=VIve zanZuUf=2gqi9~Yl=+UFkwB}$y_#}|cW^>e0$K>keKeW)?-BsOyLGWudmp(yqcc!x*dhlYf_xxRvEud3`jNt{kj zPWG%AT)&B04{&kGLJYb!w9ZjoU9&a4>Khswz#lEA%gV~EOG`^d4n1q9?rHm_9q+E& zHWHohuMAv~0PKo;v&H7O$&udPd2+XAW@f%%?&S)DRF>mxZ8?yhn_nTb`>$nx^MmoY ze?cqV?_v2Aqn9sRttvM+6Lu^M#==CHzRs;a8eP*3viN7Ak_;}n&YjKIa=QEWQt9LreMuuu1hjDFjAU*9AH zyWcM!_m(G!VYIUDP>zP7d|!Nmjwyaf7AB~E8jzGgQiYB!}-8`#>~ zCJc>^#;0@&g+lOCDq^5wI|&K-d_G?-{8C0nMieJ~Vi66Bt{LBYGu#o~*b)A9L(3=U zq@EsGwo9U41457NR#fz5g@#Ijx9ksQX>NRXP_0Z6w#$+V`wdn+8y?TY5x6)NIDDYD zx0hQNyYo=7i;GKrp^!}~T7rMv6PaY-82otN4w;~4>oX!dFkurTk6CorJY;3?Fqo%2 z#rec)A~ru1=bwL8uReVylqK^-f#Kmt1|!$yF03O?tAr$*DuJEMr4_JY{0`YEK}xj% zjU#^==eY!-;8|kv`=tolgs-t-v&?$Rk3%7cC*_riOm_e+trj$xM$G;UWe{i-NxC82 yDkJ7%p6!g;2VHJO7=6zcZ7d9ms89>rf-?ZLxiX9Ca|xr{uN^=pQV8Xi4DLU|53o!C diff --git a/TMessagesProj/src/main/res/drawable-mdpi/circle.png b/TMessagesProj/src/main/res/drawable-mdpi/circle.png new file mode 100755 index 0000000000000000000000000000000000000000..c3fb788c76c49ec0736899007d357c6f8b369587 GIT binary patch literal 1565 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWuD@%u1Od5hW46K32*3xq68pHF_1f1wh>l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|81#=KlDb#X~hD#E>34K5C;EJ)Q4 zN-fSWElLJPT$(b-ssbzLqSVBa{GyQj{2W*)24v)y2=9ZF3nBND}m`vLFhHbsTY(KatnYqyQCInmZhe+73JqDfW2&$iQ6qkIL(9V zO~LIJW1M>RfsWA!MJ!T8!-RmT2gHOYTObFX@Kf`Esl5o8tgmf)oxs4rG||(=F{I+w zlUd&0(upE%`_E*sBrmxq<|TSGtosq~OQ(fj`FCu1acTbZpo6Z3niY{d1YV^s;RUvP%~c=z>b0N0-u{4p z2TS?`fj6J>_lbP`n4|iF*>=IkhH~46jVQJSe-{z`B9yU6V-wyV{P`EenMWnCo`k&8VulscvwR*;psEvCgdE*>Q%ipYx~P zRPhPSiG5(s|7{O%4clV7^i>LJC;jH-^?x#S;P0JkQL)VD9RGFdfVl7OzTog*S>_JX zn;BKz|H^#c+;~q&H>`EloaA!`3clyrk`(hUHHjRRG5?_=DwxrblxO@yLL=0dZGPg? zRed~HyvzlJa}?azv{jYWth5sft79V62YKy+*)YRyFkge~; zfq7o4QA<0M?x`|c3cE{nC++iE&n(Tvn-j%vlJX!d;DgBPT~`@YyRWfGMm(Njyh*5A zYijYuSaX@zlYMTtR$o}Rv$1l+D!Y))DQgo$gXy_zPlYaA*u^o`#(vrc)fe{vW!I$bKKR8T z!|$fc4OaeHqUm?aIOA4L*>d+DlkTZW*Yq~6m}A2F?QWil?Y!wn` z!s=<}GuLS?$q!#0a&(`>d?}sg_@6dE)a<_%2whzlb@lXfGt(S{EXfHX4_d2!-bp*3 fZGLj8J0lyzM~#M!YSUYsK?Sy_tDnm{r-UW|Gd@ec literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/photocheck.png b/TMessagesProj/src/main/res/drawable-mdpi/photocheck.png new file mode 100755 index 0000000000000000000000000000000000000000..f21bacafa60da1d22c60861dc12aa93b13c9958d GIT binary patch literal 1946 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWuD@%u1Od5hW46K32*3xq68pHF_1f1wh>l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|81#=KlDb#X~hD#E>34K5C;EJ)Q4 zN-fSWElLJPT$(b-ssbzLqSVBa{GyQj{2W*)24v)yphK;L|rp{t37rHPB1le4RMv>2~2MaLa!T6y`ZF!TL84#CABECEH%ZgC_h&L>}9J=+-`BkX&zK> z3U0T!;MA)Rbc{YIVv!;mCIn19ASOK70y*%6pPC0u?M1+3{c!64wG0d_e4Z|jAr-ft zL}mI52a3$ywq=6eq6E=bLY)b{F0Q>!o?FZUs`(xcSBEJJUsHE%4~<+;|;|oH&~@Dxc8_S1}#+@|LRsg zdd$XC)S<7Z7bnX9{%BYH+O`FacXYb*le)_-WRi|57ZnP`i`YzmU9zgLkB|M&heIDe zd|2b~vD)*GcjqHPZK+iz9H;(PS69#d`t@rlFE8)YMu!K*TEZIl-jWFRo;RjU4 zo#p0Idgl3O-vj;bpBdJ!U285aEv;+R5pUX{8=z()omu>crwt ztjdR6I!+(?^r@&t_uk`=drmb}94Qvnz5LE&rNfpjTS83C&EvyXUtQ(uU?DTFdCxKf zwSCK$JxgRelDw}l+&SAvyLzVDGF64{IV;z!IWp~pp#;w_p6>J&H@^BDj#8N7wKLk^ z-~UA3c4;p!uWt|2*I%FQ`LW~R4F$J9Ec23oT=kl~Xzf~E2H~rJZrq5t@Uq12+=2?7 zg^xm`hE<0Em;+ih#r*R3!)k#6R6J@-NfdtlA>x?bA_3<9 zhPrjk(MN0V2+mxZ6RP^y{(h%q%_dq4b^xd zjyrz4*#FFW<+5)jGv6EY1N#p!2L<c*m&W}wz8=rr_u;Kt^uzfK%na@R&EiW#`=dd%rKhW(%Q~lo FCIBh?>9PO- literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/burn.png b/TMessagesProj/src/main/res/drawable-xhdpi/burn.png index 8fa7c27cc24c2ba59ead0c6f2b7d995628974f50..c78ed8a6d1267fab0afac8c883fd8fd9cfb07a43 100755 GIT binary patch delta 3297 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 delta 3023 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 PAG(vhn_aQZq2vDnfKNOS literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/burn.png b/TMessagesProj/src/main/res/drawable-xxhdpi/burn.png index 242852251608653201edf081213535fa7143c34d..6b91ccb6de81f240b45c7af20b674688f025d8b8 100755 GIT binary patch delta 4937 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 delta 4636 zcmZ`-cTm$yv?jEKY6R4vl+d|?bRi%up-RU9Ql!^VL+|_`AWeEin)EB6Ql%F$6hV}Z zAX24BuhNU~@@C%q^PZXAo!L2O_UzgHzHevC1pe}K#Odj%(NW)}CLtlAd#tYfgg8e1 zZ-Y=0dwu1|(i#pP(r02KQldz4Nht|wX@sb#iUdMcTwGd8OjJcg0wtoPB+3a7aKmbA z%P4!;`nuV>`#e^b<0Q@q*u#mty@D!;Vq$1+>a!bUrTm?bM3S7-R zsXPfO2hUL$fn550`-@v!FH%1ZD07oI7Vr(zAZXV#Xobl2MA8Y<1g~GdR*Bq@F;ZY5 zjBqn5Qu{J=hfFg9!1rFH!K1)_N5v5liqh*l7;<_(djiVpCbJ(m5(aVjmk$D>1V{#$ z89n)`VF7uEEVF6wLo%754nmwFIQ3N8mw+b7E)q0w!=T9URDxbXx;ht}sY}`_>1`-o zHiflz6coflkYjct%j4~IdPTmk+YVG zpXNy*f9*kOScc*Rq#dC5Kr}#jOoC{_FdRb5YWYhmU%iNR&9wxdV)znQO)gJHiw~l( z_(-A36%(;-!$3a4d>bowL_u{K;fvpXO>)G5hLFa@HqR*BQlUCu74jn!t`Us=hp;{h zwI1f+X3QMOhF8ytyx4rJpe`a?E%YII^DSOa7~;dWN~Wga$HMW*hO59W{)KW(lz;1iX)xP3}-9VUaDxAlo45884R=BQi&d0R8poTM)O=MUX z6sHLOV_%SLcMsnYGf8+&iR>po*OU~M9;O`1HihDw^G55*WuU6AHVnuF(!ms0MOFvs zG|UicoD&d-7fX=k&b$NrpgQMaGBVeE{qg_Jd&O0Y30CZ?B=mX@Y0 zKysCf$D^UQZlzC*jEp?+vR)=bkAE!i*tqMcmhAY^kck?2{^AL3?3XWJ_Tlk?gM)*w zIPY`^*eFHPGH23<>dPo{2tCKahG`$JT;_BT+up&*x;SBgNa~5y(M0I0hBTUpLDyCWc)Z zre-)C=hN(dy0=i-*VjiwXso{TmY*}$Es%yZots*Xra0Dfspo7XNG__hi=G8h&CSi- ztrLZV6;x!TU;@!)#->*5qi^PZDNXJ(rJ_wur-074=u(+@J*L9!ur09%sn4C_pB}6Z zv6l{A6qLf+ZF`dfu!zqqPNtZ6gxy`6iBjbyBLOCz!oot^!_ZIf-*2Y$_iKsLv+H^~ zdueWvN8AgE>-lEU9&(1z)ch8<{d9e0MUp8fJ}~qAb}F1Dw&H>*%E`zKnTff{%IcPK z{sO3~s`|0N)O-DVagnn`!e8AIN2n1~6uh3kC18}WC2&Fj%gf8>t*@^O8=IK)DUT|H z92^`Zr^q9`_xnHZDb&~2iUX^;{!G#ByWMe&y{z&fr-7*uQa3r%9C%Os8-L@EK}Ti8 zQ=@(onI&egf%Wq8da0g$Uk?wj-b{I+0zfri31;zQ`5(E>w)i4Bo$d$jS}T<>n8(_< zYH4UtA08hcL(jb#7#STu9#6SgBuHhH``3+_k#KdxDa)NvWp71#9O+mPSi`xk6 z+Qa!)e-GL&Z7J9#WOWV){VaAR{OQswEiy9l@z;r3hkp4iw}$VFx* z3~%K0>2&c$2COnL;P`g8$OHvwaMlO=N6XZuy0*4YfGTt39a#56ZHo?t_FKyp!=ag2QNmFBGz{d)L00vqmUp9ni}=?SFZ@%WBa*-m5U z3A)(C#99BdKflF7cOp2=8{Ju5C`7hG#yDJy?igk49xm8N-o26B84QAk56?7k74fczH|0 zEjxl~tfA?jvmd$`1KIh`i8w2Fx#EnBjPd>~aSBaTA=<>y@CfTTIS*X_l{vkibv~n6 zs23$t$Iu_$$F^9UEPvO-#YMn)`%QCm^P3MJK2)4|3mBCn(9fQQr27jxVlewFIUY$4 zkD<2(<3L<5C}?iWK3H~?kd&MQe=00K@m|vvv}i+A+$vBL20G&5f_hM`?TeI@6p_)n zIg8;l@c8)n(MFy^@UiRPJh@<<{g3&jrKR_{27gCt@t|GkEJF5GI#xqpWn{R>PH+4@ znOC5o=c_6s3(-7~nhS`0?sH61QqsQ=%?1L2yb2Y-oG&!AtJ2fc>n|@4hT2&Bi5G}B z4d9P8G9s@5oX6iO77Ao%Mury_KACctGnUzGon4RXCP5&aM#EC63=?z8_aBYIH4Wk5ot>TMy1R=OMw$9$(-nR<7*GE4r5BByaD$FX>lGz5({sTb0 z%MW++7N5tf?2toVsnhQW7FJeF{?EAtT$v*hT3J~c^weJ9{{0=-*_NXP;p<*@plx_$ zWPg&Qj0j*ku)$6+5d&OByrh7l2Xc0R*? znWV~g4W8OmeK`3gGYV5`4uwf>9LVpney1mcipg&=d(1TH*I>pKH54wNxjX3ZPhp zsCfI9(b0I_>%pn08*?=N_{awY9aq8ahI_1but;;7;PNEz@w10`wu4xEoWVqYN5H!na31 z#8I+-y1#^b)Gs6?WaQw`au$C_*rMD@1v-h9@OONss@mfwZ-Ug)jjZJlz*q`pY)S;v z1eX)dtggjr@914H4XNjI2jpu7pdA!VmwT_Su&{$4c$i&XEs}fup)+A6l}pWuZl8Us zy%DZ~_zJq&705ORycnJbONr1?Q;%ZIF@Ao>mLF^1yew4Cg=;*9XgrX=zC7sM*l^Be z5r>(RC!ZA;6}=|JtkteX8-CZ7KU=1KGccv%dYuW+4!3`~$|-|>^2Ep4*p?}6adGj| zr>`InAigS4o}QkJZw5>$uaxjINI13h*ZmGK`?8UNfx)qFE|EoFBqk;n;A3rVY|dq4 zipi?|wx?L)a}ICjyq7e-nX+Gb8s-viav)gwbgRo+m(RhHau5QJ>xPpULr;#G2P#5l=_!Yx^JwC`GA}f5ig1(=O-Zli~ufR~o#+kD>6fU8O!7A^9Lzj9I!3C`f#mO)+ zaq%S_4yWqe!Yd_pQq|PdB-eC|k0?RSZ+?kfQ2e|wZq#6S%+Sx$90j1afV1BjMI|LA z)E*ulW+Ka6j~b(*qtBJfCST>{g+(S0k;rLYeo5u}yQ~356 zN=8r0Zc<-4rL@M7pT7jldMAt&7>*7-PHKUW_V)f|QMyo92LfnkyQ6cXq2#2F-WVhDRVL$7U<052d z;uS}|g0Er@z_fm`ay7^;1L{wARiqna%)yp0kdumA@uWS_qOa>{znbfY;s`!YVteoG z81W1DYmj_&I6YOiX#{1%EhtCz!1Xs~Co_H}58Oi%*o~K(eqz*LzueH@b-Q8kZ6381 zAFW3DiS{sKi>GNQWoACF1BO%lCELFm(UCSw4sss=+I~RgBWuVDyA29(wp-7H<0B?6 z*!P+`+@0)@a8=MMHX(Ogg=1Kku!T)U-f|#C!uPndC={ReRR)1*42^R{P7PGiRH${= z#k3ZYzV^28F*+?JlG>k&^jlE87 z^eNIOdV~IHn!5a_l8@qwo8->iqO;GlM7OlsA*b6>3~R2cX->-J%`c1?$^EENL6&=4|GRkj*+(IRLmzCI_dtY1$e(4P_oyD zzFXLUp`;y~&RC);-5Ifon?IQjg>9pfb>G1aLg^GngHJt6bbV&|78d81Q{(KDZ5X2N z?-ls!b}n!?a(pkruyQ+w=VY4m*?D~<7o|a&hjnE^DE!MCx#~DLD(Uvs`h%Z03%l9% x?{d$EhzGjD%Xy-!7WfsU6)lmMmf;{0*LPvIQp^K#3aImksSjl|VjetSFLik}g z*gr{m5nZ8nEG`{t3O6wdFh(Mw7z`YVHpO6&hES9-5`{39+!!My8f%KdqRgP*E|?@5 zH!uiGA~<}DC9!a@5I&!cMIfT0qTo>`a27WhfwZu&Sk*wGj3fvnUUUSXDlm%R{rX*j zK<5Q;8Eig-6#-pUq|#WCd>l-Y=|3ef**|0>c;B{3vSA1Tm5o5cjaN(h4kQx)Ka|P* zf#&f^^ndgHpTazHG@Fhf(Rr*$Zh++Af__~M#m3rk=~O<8OJ=dczwe@J2#e3+g|OIA zJ9i9J&yx`m$cp0Wf5j7tSf>acpBfQBcOu|m5(PMe5r{>iG4>dO0}}0EV~RxDqs<9s z1bc!R%FMxmV2nmueCHBa0g+641phlX@Lw+Kr`*+6V6r8V33M*wH+rB0m&JsBEg8%B zX)g8-Kh^uj4g7g7#y{mEB*`FF5B9$f`nyZgJ*(3nZ7VT;G(J5-((PPHTMzsNhf7Jx zjyn--$bzw#`LnFOd)2zk;^OfTx)5J`)KpF{6{w0#mvT@=cCJzW<5-%_7lkhh+q7eC z@XCPuN;y&~;8eVt@mir=roN1ij-9*=<=w_@j>&V;{3Tv^x$mmQ(8e>|D);i zThpx_L^>7S>gA6j~Eq72akjOGv?3COrn7Sn}t-dghIJ)!62k@DTlzYcF4 z%SJ1wRK5@;$JWgE)`$uwG=?Tn$_>9*k#K$Q%r?PA4ZA^1Z4NjjJv4vL>1ItW*Y3?# zkwG7@-J_Gjp}-wK7VhBY4s#5O&jUm2sA1rzw^RPSl~VT>4UtvwtI%$V!+HZ`-Z+cP z(O}srZ=-#hdo;ZGk5#Uw6=9T9s!nA`tLCRQI9TM_GYW&r^WMwFMLJ_J=NdN}C`tc4 zu)l$1x??=V{ZqY$JsGQD?KkA?8fAT zOSuVN=F{?)E>~JSY+iNYvm!Yc(FHPZ1e<%MH_H;29#`K%IBI&SH~lhUTZK9S-Q*R5~sc(grP4cUV`Cq6Wt&_?oJueuAz@f!c@& z)0re}mtvtk@8S{iF5beqF7(1uBc%t=TK}%aF;cFp!^^#AWu$jSs8PS`J|m9?z*T6h zS|HP!j{|t-afKyEpArxuRsHk11mn2rF{PzmLKJpUBP4}AnYohNKcHu-y!Bv+K1R8Q z0y~&Z35Q}%sB-6pT zl!Ud#NzxfUJdx^p7BJ6Z7Dx<+ktSw3g076TCsZ9LjXFW#hN zKrgfs+jk!sF6_ARXVy?Nihbv`Om`~z522cG11Y9*I@8>9vnuK2!R1tPFJ7thy1^N< zw?b~7`!7{N&{29F#DJ6%N4mnIECg;RseLGR(#Mr_c$R>Y=yUhmOGh)>G*6?#lF#&a zZ`rtT;&hwSi;(LsYTIK0{YP;nIrko_yr|y~NEjD+LUt6rJS*p0AqFL}ZgtUOLF}7t zy~_!^3Jix=g7O|_4S=U|7Q@kUfraCk&6DjkD+^Df4+5m}Oamo#fOPNay?Gz8HB}*L zOZ*44K;QSK`33C0`D1cghrqw>-@m-{M*B&jZ$Ps^@bQAD-Q#PSn2g#!8S9Gvn7?hU zAuo=ax7c2UJl%76*{`{4(m81hK;fY)ra&e#$VRu@V~I2Tghf1@7?Wj=v(rBCk=9ig zoEWH@wcsvBckgib=ReZ6+Ce(3XrDnYC{Hn2$j*+8E18o^Cni3#QVrS^P_X{3L&{dzfPCNXpvM#46>!g{FTc5%xpVM)4%JtKt zTh;U)GE>>FAbS(LrOP4hS(>36T(;=%@O<-mg7)=iFQ0A_C+i*b8aC)1s2Gtm^UaV8 z&1X(<3My29s<~q|n|@EpLSH7<+V$qW+Le>AZ$lMLXBTmvseej*u;D=QOj>!g zsn82(t3xpi�ab5Zh|nq~cU%xP>X4=JL1ge=bt`U5NRzZ;nLS4=;`!;M5G?HQNh zf?dG#!Wat%!f^J>U7tS3DhpHRBaqTx%Mr##9i5FT0vn3?&hH_da$i(fZY8G_cC z=cWJ~EIbT0lKeG>(YjrX*K!W?2oMntL9mMC(#0R%PnGM_4 zsQuwJ+uiZt_VC|Pv=dV~vqi)flLPM@wbbX0pHofL2U^ejZ`qmckdqUx$M@{|5I)n^ t%c?2A&EK6jWfc2z*9YPAbBAQWQWsOBUp%O6vsnH0cd~aTRNML|{s+0@PR9TM literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/photocheck.png b/TMessagesProj/src/main/res/drawable-xxhdpi/photocheck.png new file mode 100755 index 0000000000000000000000000000000000000000..fa83dc2bd84381660ba1a12b29a42f15c9b7cb4e GIT binary patch literal 4201 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 literal 0 HcmV?d00001 From ad863779f799ea51c37d4a41e76fd7006339ef3e Mon Sep 17 00:00:00 2001 From: DrKLO Date: Fri, 10 Oct 2014 21:16:39 +0400 Subject: [PATCH 03/18] Different improvements --- TMessagesProj/build.gradle | 4 +- .../org/telegram/android/ImageLoader.java | 4 + .../org/telegram/android/MessageObject.java | 8 +- .../telegram/android/MessagesController.java | 15 +- .../org/telegram/android/MessagesStorage.java | 15 +- .../telegram/android/NotificationCenter.java | 1 + .../java/org/telegram/messenger/TLRPC.java | 1 + .../org/telegram/ui/Cells/ChatBaseCell.java | 5 + .../org/telegram/ui/Cells/ChatMediaCell.java | 27 +-- .../java/org/telegram/ui/ChatActivity.java | 193 +++++++++++++----- .../java/org/telegram/ui/PhotoViewer.java | 4 +- .../org/telegram/ui/SecretPhotoViewer.java | 111 +++++++++- .../org/telegram/ui/Views/LayoutListView.java | 18 ++ .../src/main/res/drawable-hdpi/circle1.png | Bin 0 -> 1569 bytes .../src/main/res/drawable-ldpi/circle1.png | Bin 0 -> 1216 bytes .../src/main/res/drawable-mdpi/circle1.png | Bin 0 -> 1344 bytes .../src/main/res/drawable-xhdpi/circle1.png | Bin 0 -> 1815 bytes .../src/main/res/drawable-xxhdpi/circle1.png | Bin 0 -> 2347 bytes 18 files changed, 302 insertions(+), 104 deletions(-) create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/circle1.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/circle1.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/circle1.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/circle1.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/circle1.png diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index 52181cf0..a0173758 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -80,7 +80,7 @@ android { defaultConfig { minSdkVersion 8 targetSdkVersion 19 - versionCode 355 - versionName "1.9.4" + versionCode 357 + versionName "1.9.5" } } diff --git a/TMessagesProj/src/main/java/org/telegram/android/ImageLoader.java b/TMessagesProj/src/main/java/org/telegram/android/ImageLoader.java index 2d542493..cdee9073 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/ImageLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/android/ImageLoader.java @@ -831,6 +831,10 @@ public class ImageLoader { }); } + public void putImageToCache(BitmapDrawable bitmap, String key) { + memCache.put(key, bitmap); + } + public void loadImage(final TLRPC.FileLocation fileLocation, final String httpUrl, final ImageReceiver imageView, final int size, final boolean cacheOnly) { if ((fileLocation == null && httpUrl == null) || imageView == null || (fileLocation != null && !(fileLocation instanceof TLRPC.TL_fileLocation) && !(fileLocation instanceof TLRPC.TL_fileEncryptedLocation))) { return; diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java index dad8b492..f01e0b35 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java @@ -616,7 +616,7 @@ public class MessageObject { } public boolean isSecretMedia() { - return messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && messageOwner.ttl != 0; + return messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && messageOwner.ttl != 0 && messageOwner.ttl <= 60; } public static void setIsUnread(TLRPC.Message message, boolean unread) { @@ -672,12 +672,8 @@ public class MessageObject { String str; if (secondsLeft < 60) { str = secondsLeft + "s"; - } else if (secondsLeft < 60 * 60) { - str = secondsLeft / 60 + "m"; - } else if (secondsLeft < 60 * 60 * 24) { - str = secondsLeft / 60 / 60 + "h"; } else { - str = secondsLeft / 60 / 60 / 24 + "d"; + str = secondsLeft / 60 + "m"; } return str; } diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java index 1fdba71a..da42b019 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java @@ -17,6 +17,7 @@ import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.os.Build; import android.text.Html; +import android.util.SparseArray; import org.telegram.messenger.BuffersStorage; import org.telegram.messenger.ByteBufferDesc; @@ -502,7 +503,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } - public void didAddedNewTask(final int minDate) { + public void didAddedNewTask(final int minDate, final SparseArray> mids) { Utilities.stageQueue.postRunnable(new Runnable() { @Override public void run() { @@ -511,6 +512,12 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } }); + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.didCreatedNewDeleteTask, mids); + } + }); } public void getNewDeleteTask(final ArrayList oldTask) { @@ -3552,7 +3559,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter newMessage.media.photo.date = newMessage.date; newMessage.media.photo.caption = ""; newMessage.media.photo.geo = new TLRPC.TL_geoPointEmpty(); - if (decryptedMessage.media.thumb.length != 0 && decryptedMessage.media.thumb.length <= 5000 && decryptedMessage.media.thumb_w < 100 && decryptedMessage.media.thumb_h < 100) { + if (decryptedMessage.media.thumb.length != 0 && decryptedMessage.media.thumb.length <= 6000 && decryptedMessage.media.thumb_w <= 100 && decryptedMessage.media.thumb_h <= 100) { TLRPC.TL_photoCachedSize small = new TLRPC.TL_photoCachedSize(); small.w = decryptedMessage.media.thumb_w; small.h = decryptedMessage.media.thumb_h; @@ -3581,7 +3588,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } newMessage.media = new TLRPC.TL_messageMediaVideo(); newMessage.media.video = new TLRPC.TL_videoEncrypted(); - if (decryptedMessage.media.thumb.length != 0 && decryptedMessage.media.thumb.length <= 5000 && decryptedMessage.media.thumb_w < 100 && decryptedMessage.media.thumb_h < 100) { + if (decryptedMessage.media.thumb.length != 0 && decryptedMessage.media.thumb.length <= 6000 && decryptedMessage.media.thumb_w <= 100 && decryptedMessage.media.thumb_h <= 100) { newMessage.media.video.thumb = new TLRPC.TL_photoCachedSize(); newMessage.media.video.thumb.bytes = decryptedMessage.media.thumb; newMessage.media.video.thumb.w = decryptedMessage.media.thumb_w; @@ -3623,7 +3630,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter newMessage.media.document.size = message.file.size; newMessage.media.document.key = decryptedMessage.media.key; newMessage.media.document.iv = decryptedMessage.media.iv; - if (decryptedMessage.media.thumb.length != 0 && decryptedMessage.media.thumb.length <= 5000 && decryptedMessage.media.thumb_w < 100 && decryptedMessage.media.thumb_h < 100) { + if (decryptedMessage.media.thumb.length != 0 && decryptedMessage.media.thumb.length <= 6000 && decryptedMessage.media.thumb_w <= 100 && decryptedMessage.media.thumb_h <= 100) { newMessage.media.document.thumb = new TLRPC.TL_photoCachedSize(); newMessage.media.document.thumb.bytes = decryptedMessage.media.thumb; newMessage.media.document.thumb.w = decryptedMessage.media.thumb_w; diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java index b93081e0..592b6e29 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java @@ -882,7 +882,7 @@ public class MessagesStorage { state.dispose(); database.commitTransaction(); database.executeFast(String.format(Locale.US, "UPDATE messages SET ttl = 0 WHERE mid IN(%s)", mids.toString())).stepThis().dispose(); - MessagesController.getInstance().didAddedNewTask(minDate); + MessagesController.getInstance().didAddedNewTask(minDate, messages); } } catch (Exception e) { FileLog.e("tmessages", e); @@ -2432,15 +2432,10 @@ public class MessagesStorage { } private int getMessageMediaType(TLRPC.Message message) { - if (message.media == null) { - return 0; - } else if (message.media instanceof TLRPC.TL_messageMediaPhoto) { + if (message.media instanceof TLRPC.TL_messageMediaPhoto && message.ttl != 0 && message.ttl <= 60) { return 1; - } else if (message.media instanceof TLRPC.TL_messageMediaVideo) { - return 2; - } else { - return 0; } + return 0; } private void putMessagesInternal(final ArrayList messages, final boolean withTransaction, final boolean isBroadcast, final int downloadMask) { @@ -2478,7 +2473,7 @@ public class MessagesStorage { messagesIdsMap.put(message.id, dialog_id); } - if (message.ttl == 0 && (message.media instanceof TLRPC.TL_messageMediaVideo || message.media instanceof TLRPC.TL_messageMediaPhoto)) { + if (message.media instanceof TLRPC.TL_messageMediaVideo || message.media instanceof TLRPC.TL_messageMediaPhoto && (message.ttl == 0 || message.ttl > 60)) { if (messageMediaIds.length() > 0) { messageMediaIds.append(","); } @@ -2562,7 +2557,7 @@ public class MessagesStorage { state3.step(); } - if (message.ttl == 0 && (message.media instanceof TLRPC.TL_messageMediaVideo || message.media instanceof TLRPC.TL_messageMediaPhoto)) { + if (message.media instanceof TLRPC.TL_messageMediaVideo || message.media instanceof TLRPC.TL_messageMediaPhoto && (message.ttl == 0 || message.ttl > 60)) { state2.requery(); state2.bindInteger(1, messageId); state2.bindLong(2, dialog_id); diff --git a/TMessagesProj/src/main/java/org/telegram/android/NotificationCenter.java b/TMessagesProj/src/main/java/org/telegram/android/NotificationCenter.java index 87298e13..2a53670a 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/NotificationCenter.java +++ b/TMessagesProj/src/main/java/org/telegram/android/NotificationCenter.java @@ -41,6 +41,7 @@ public class NotificationCenter { public static final int openedChatChanged = 29; public static final int hideEmojiKeyboard = 30; public static final int stopEncodingService = 31; + public static final int didCreatedNewDeleteTask = 32; public static final int wallpapersDidLoaded = 171; public static final int closeOtherAppActivities = 702; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java index e86ad58f..eb33d919 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java @@ -9333,6 +9333,7 @@ public class TLRPC { public byte[] auth_key; public int user_id; public int ttl; + public int layer; } public static class FileLocation extends TLObject { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java index 2577049d..3ce74277 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java @@ -118,6 +118,7 @@ public class ChatBaseCell extends BaseCell { private CheckForTap pendingCheckForTap = null; private int last_send_state = 0; + private int last_delete_date = 0; private final class CheckForTap implements Runnable { public void run() { @@ -219,6 +220,9 @@ public class ChatBaseCell extends BaseCell { if (last_send_state != currentMessageObject.messageOwner.send_state) { return true; } + if (last_delete_date != currentMessageObject.messageOwner.destroyTime) { + return true; + } TLRPC.User newUser = MessagesController.getInstance().getUser(currentMessageObject.messageOwner.from_id); TLRPC.FileLocation newPhoto = null; @@ -251,6 +255,7 @@ public class ChatBaseCell extends BaseCell { public void setMessageObject(MessageObject messageObject) { currentMessageObject = messageObject; last_send_state = messageObject.messageOwner.send_state; + last_delete_date = messageObject.messageOwner.destroyTime; isPressed = false; isCheckPressed = true; isAvatarVisible = false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java index f1abc028..467f0371 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java @@ -42,8 +42,6 @@ import java.util.Locale; public class ChatMediaCell extends ChatBaseCell implements MediaController.FileDownloadProgressListener { public static interface ChatMediaCellDelegate { - public abstract boolean didPressedImage(ChatMediaCell cell); - public abstract void didUnpressedImage(ChatMediaCell cell); public abstract void didClickedImage(ChatMediaCell cell); public abstract void didPressedOther(ChatMediaCell cell); } @@ -85,7 +83,6 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD private boolean otherPressed = false; private int buttonX; private int buttonY; - private boolean listenForUnpressed = false; private StaticLayout infoLayout; private int infoWidth; @@ -212,10 +209,8 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD } } } - listenForUnpressed = false; - if (imagePressed && mediaDelegate != null && mediaDelegate.didPressedImage(this)) { + if (imagePressed && currentMessageObject.isSecretMedia()) { imagePressed = false; - listenForUnpressed = true; } else if (result) { startCheckLongPress(); } @@ -242,8 +237,10 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD } else if (imagePressed) { if (event.getAction() == MotionEvent.ACTION_UP) { imagePressed = false; - playSoundEffect(SoundEffectConstants.CLICK); - didClickedImage(); + if (buttonState == -1 || buttonState == 2 || buttonState == 3) { + playSoundEffect(SoundEffectConstants.CLICK); + didClickedImage(); + } invalidate(); } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { imagePressed = false; @@ -277,14 +274,6 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD } } } - } else if (listenForUnpressed) { - if (event.getAction() == MotionEvent.ACTION_POINTER_UP || event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { - if (listenForUnpressed && mediaDelegate != null) { - mediaDelegate.didUnpressedImage(this); - } - listenForUnpressed = false; - } - result = true; } } if (!result) { @@ -575,6 +564,10 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD w = timeWidthTotal; } + if (currentMessageObject.isSecretMedia()) { + w = h = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.5f); + } + photoWidth = w; photoHeight = h; backgroundWidth = w + AndroidUtilities.dp(12); @@ -785,7 +778,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD } private void updateSecretTimeText() { - if (currentMessageObject == null) { + if (currentMessageObject == null || currentMessageObject.isOut()) { return; } String str = currentMessageObject.getSecretTimeString(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 151f2b02..16284f91 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -32,6 +32,7 @@ import android.os.Bundle; import android.provider.MediaStore; import android.text.Html; import android.text.TextUtils; +import android.util.SparseArray; import android.util.TypedValue; import android.view.Gravity; import android.view.LayoutInflater; @@ -175,6 +176,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private String startVideoEdit = null; private Runnable openSecretPhotoRunnable = null; + private float startX = 0; + private float startY = 0; private final static int copy = 1; private final static int forward = 2; @@ -188,6 +191,27 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private final static int attach_location = 10; private final static int chat_menu_avatar = 11; + AdapterView.OnItemLongClickListener onItemLongClickListener = new AdapterView.OnItemLongClickListener() { + @Override + public boolean onItemLongClick(AdapterView adapter, View view, int position, long id) { + if (!actionBarLayer.isActionModeShowed()) { + createMenu(view, false); + } + return true; + } + }; + + AdapterView.OnItemClickListener onItemClickListener = new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, int i, long l) { + if (actionBarLayer.isActionModeShowed()) { + processRowSelect(view); + return; + } + createMenu(view, true); + } + }; + public ChatActivity(Bundle args) { super(args); } @@ -350,6 +374,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not NotificationCenter.getInstance().addObserver(this, NotificationCenter.screenshotTook); NotificationCenter.getInstance().addObserver(this, NotificationCenter.blockedUsersDidLoaded); NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileNewChunkAvailable); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.didCreatedNewDeleteTask); super.onFragmentCreate(); @@ -397,6 +422,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not NotificationCenter.getInstance().removeObserver(this, NotificationCenter.screenshotTook); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.blockedUsersDidLoaded); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.FileNewChunkAvailable); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didCreatedNewDeleteTask); if (AndroidUtilities.isTablet()) { NotificationCenter.getInstance().postNotificationName(NotificationCenter.openedChatChanged, dialog_id, true); } @@ -746,17 +772,103 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not emptyView.setText(LocaleController.getString("GotAQuestion", R.string.GotAQuestion)); } - chatListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { + chatListView.setOnItemLongClickListener(onItemLongClickListener); + chatListView.setOnItemClickListener(onItemClickListener); + + final Rect scrollRect = new Rect(); + + chatListView.setOnInterceptTouchEventListener(new LayoutListView.OnInterceptTouchEventListener() { @Override - public boolean onItemLongClick(AdapterView adapter, View view, int position, long id) { - if (!actionBarLayer.isActionModeShowed()) { - createMenu(view, false); + public boolean onInterceptTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + int x = (int)event.getX(); + int y = (int)event.getY(); + int count = chatListView.getChildCount(); + Rect rect = new Rect(); + for (int a = 0; a < count; a++) { + View view = chatListView.getChildAt(a); + int top = view.getTop(); + int bottom = view.getBottom(); + view.getLocalVisibleRect(rect); + if (top > y || bottom < y) { + continue; + } + if (!(view instanceof ChatMediaCell)) { + break; + } + final ChatMediaCell cell = (ChatMediaCell)view; + final MessageObject messageObject = cell.getMessageObject(); + if (messageObject == null || !messageObject.isSecretMedia() || !cell.getPhotoImage().isInsideImage(x, y - top)) { + break; + } + startX = x; + startY = y; + openSecretPhotoRunnable = new Runnable() { + @Override + public void run() { + if (openSecretPhotoRunnable == null) { + return; + } + chatListView.requestDisallowInterceptTouchEvent(true); + chatListView.setOnItemLongClickListener(null); + chatListView.setOnItemClickListener(null); + chatListView.setLongClickable(false); + openSecretPhotoRunnable = null; + if (!messageObject.isOut() && messageObject.messageOwner.destroyTime == 0) { + MessagesController.getInstance().markMessageAsRead(dialog_id, messageObject.messageOwner.random_id); + messageObject.messageOwner.destroyTime = messageObject.messageOwner.ttl + ConnectionsManager.getInstance().getCurrentTime(); + cell.invalidate(); + } + SecretPhotoViewer.getInstance().setParentActivity(getParentActivity()); + SecretPhotoViewer.getInstance().openPhoto(messageObject); + } + }; + AndroidUtilities.RunOnUIThread(openSecretPhotoRunnable, 100); + return true; + } } - return true; + return false; } }); - final Rect scrollRect = new Rect(); + chatListView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_POINTER_UP) { + if (openSecretPhotoRunnable != null) { + AndroidUtilities.CancelRunOnUIThread(openSecretPhotoRunnable); + openSecretPhotoRunnable = null; + } else { + if (SecretPhotoViewer.getInstance().isVisible()) { + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + chatListView.setOnItemLongClickListener(onItemLongClickListener); + chatListView.setOnItemClickListener(onItemClickListener); + chatListView.setLongClickable(true); + } + }); + SecretPhotoViewer.getInstance().closePhoto(); + } + } + } else if (event.getAction() != MotionEvent.ACTION_DOWN) { + if (SecretPhotoViewer.getInstance().isVisible()) { + return true; + } else if (openSecretPhotoRunnable != null) { + if (event.getAction() == MotionEvent.ACTION_MOVE) { + if (Math.hypot(startX - event.getX(), startY - event.getY()) > AndroidUtilities.dp(5)) { + AndroidUtilities.CancelRunOnUIThread(openSecretPhotoRunnable); + openSecretPhotoRunnable = null; + } + } else { + AndroidUtilities.CancelRunOnUIThread(openSecretPhotoRunnable); + openSecretPhotoRunnable = null; + } + } + } + return false; + } + }); chatListView.setOnScrollListener(new AbsListView.OnScrollListener() { @Override @@ -856,17 +968,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }); - chatListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView adapterView, View view, int i, long l) { - if (actionBarLayer.isActionModeShowed()) { - processRowSelect(view); - return; - } - createMenu(view, true); - } - }); - updateBottomOverlay(); chatActivityEnterView.setContainerView(getParentActivity(), fragmentView); @@ -2396,6 +2497,23 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not updateVisibleRows(); } } + } else if (id == NotificationCenter.didCreatedNewDeleteTask) { + SparseArray> mids = (SparseArray>)args[0]; + boolean changed = false; + for(int i = 0; i < mids.size(); i++) { + int key = mids.keyAt(i); + ArrayList arr = mids.get(key); + for (Integer mid : arr) { + MessageObject messageObject = messagesDict.get(mid); + if (messageObject != null) { + messageObject.messageOwner.destroyTime = key; + changed = true; + } + } + } + if (changed) { + updateVisibleRows(); + } } } @@ -2574,6 +2692,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }); } + + chatListView.setOnItemLongClickListener(onItemLongClickListener); + chatListView.setOnItemClickListener(onItemClickListener); + chatListView.setLongClickable(true); } @Override @@ -3505,43 +3627,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not public void didPressedOther(ChatMediaCell cell) { createMenu(cell, true); } - - @Override - public boolean didPressedImage(final ChatMediaCell cell) { - final MessageObject messageObject = cell.getMessageObject(); - if (messageObject == null || !messageObject.isSecretMedia()) { - return false; - } - openSecretPhotoRunnable = new Runnable() { - @Override - public void run() { - if (openSecretPhotoRunnable == null) { - return; - } - chatListView.requestDisallowInterceptTouchEvent(true); - openSecretPhotoRunnable = null; - if (!messageObject.isOut() && messageObject.messageOwner.destroyTime == 0) { - MessagesController.getInstance().markMessageAsRead(dialog_id, message.messageOwner.random_id); - messageObject.messageOwner.destroyTime = messageObject.messageOwner.ttl + ConnectionsManager.getInstance().getCurrentTime(); - cell.invalidate(); - } - SecretPhotoViewer.getInstance().setParentActivity(getParentActivity()); - SecretPhotoViewer.getInstance().openPhoto(messageObject); - } - }; - AndroidUtilities.RunOnUIThread(openSecretPhotoRunnable, 100); - return true; - } - - @Override - public void didUnpressedImage(ChatMediaCell cell) { - if (openSecretPhotoRunnable != null) { - AndroidUtilities.CancelRunOnUIThread(openSecretPhotoRunnable); - openSecretPhotoRunnable = null; - } else { - SecretPhotoViewer.getInstance().closePhoto(); - } - } }; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index 8140abcd..7fdf85c4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -234,7 +234,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat public int getSelectedCount(); } - private static class FrameLayoutTouchListener extends FrameLayout { + private class FrameLayoutTouchListener extends FrameLayout { public FrameLayoutTouchListener(Context context) { super(context); } @@ -251,7 +251,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } - private static class FrameLayoutDrawer extends FrameLayout { + private class FrameLayoutDrawer extends FrameLayout { public FrameLayoutDrawer(Context context) { super(context); setWillNotDraw(false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SecretPhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/SecretPhotoViewer.java index b7e585ff..3dd8e29d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SecretPhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SecretPhotoViewer.java @@ -11,27 +11,36 @@ package org.telegram.ui; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.RectF; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.text.Layout; import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; +import android.util.SparseArray; import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; import android.view.WindowManager; import android.widget.FrameLayout; import org.telegram.android.AndroidUtilities; +import org.telegram.android.ImageLoader; import org.telegram.android.ImageReceiver; import org.telegram.android.MessageObject; import org.telegram.android.NotificationCenter; import org.telegram.messenger.ConnectionsManager; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; +import org.telegram.messenger.R; import org.telegram.messenger.TLRPC; +import java.io.File; import java.util.ArrayList; public class SecretPhotoViewer implements NotificationCenter.NotificationCenterDelegate { @@ -48,6 +57,18 @@ public class SecretPhotoViewer implements NotificationCenter.NotificationCenterD } } + private class FrameLayoutTouchListener extends FrameLayout { + public FrameLayoutTouchListener(Context context) { + super(context); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + FileLog.e("tmessages", event.toString()); + return super.onTouchEvent(event); + } + } + private class SecretDeleteTimer extends FrameLayout { private String currentInfoString; private int infoWidth; @@ -55,6 +76,7 @@ public class SecretPhotoViewer implements NotificationCenter.NotificationCenterD private StaticLayout infoLayout = null; private Paint deleteProgressPaint; private RectF deleteProgressRect = new RectF(); + private Drawable drawable = null; public SecretDeleteTimer(Context context) { super(context); @@ -66,6 +88,8 @@ public class SecretPhotoViewer implements NotificationCenter.NotificationCenterD deleteProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG); deleteProgressPaint.setColor(0xffe6e6e6); + + drawable = getResources().getDrawable(R.drawable.circle1); } private void updateSecretTimeText() { @@ -88,14 +112,20 @@ public class SecretPhotoViewer implements NotificationCenter.NotificationCenterD @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); - deleteProgressRect.set(getMeasuredWidth() - AndroidUtilities.dp(27), 0, getMeasuredWidth(), AndroidUtilities.dp(27)); + deleteProgressRect.set(getMeasuredWidth() - AndroidUtilities.dp(30), AndroidUtilities.dp(2), getMeasuredWidth() - AndroidUtilities.dp(2), AndroidUtilities.dp(30)); } @Override protected void onDraw(Canvas canvas) { - if (currentMessageObject == null) { + if (currentMessageObject == null || currentMessageObject.messageOwner.destroyTime == 0) { return; } + + if (drawable != null) { + drawable.setBounds(getMeasuredWidth() - AndroidUtilities.dp(32), 0, getMeasuredWidth(), AndroidUtilities.dp(32)); + drawable.draw(canvas); + } + long msTime = System.currentTimeMillis() + ConnectionsManager.getInstance().getTimeDifference() * 1000; float progress = Math.max(0, (long)currentMessageObject.messageOwner.destroyTime * 1000 - msTime) / (currentMessageObject.messageOwner.ttl * 1000.0f); canvas.drawArc(deleteProgressRect, -90, -360 * progress, true, deleteProgressPaint); @@ -107,7 +137,7 @@ public class SecretPhotoViewer implements NotificationCenter.NotificationCenterD if (infoLayout != null) { canvas.save(); - canvas.translate(getMeasuredWidth() - AndroidUtilities.dp(34) - infoWidth, AndroidUtilities.dp(5)); + canvas.translate(getMeasuredWidth() - AndroidUtilities.dp(38) - infoWidth, AndroidUtilities.dp(7)); infoLayout.draw(canvas); canvas.restore(); } @@ -116,10 +146,11 @@ public class SecretPhotoViewer implements NotificationCenter.NotificationCenterD private Activity parentActivity; private WindowManager.LayoutParams windowLayoutParams; - private FrameLayout windowView; + private FrameLayoutTouchListener windowView; private FrameLayoutDrawer containerView; private ImageReceiver centerImage = new ImageReceiver(); private SecretDeleteTimer secretDeleteTimer; + private boolean isVisible = false; private MessageObject currentMessageObject = null; @@ -148,6 +179,22 @@ public class SecretPhotoViewer implements NotificationCenter.NotificationCenterD if (markAsDeletedMessages.contains(currentMessageObject.messageOwner.id)) { closePhoto(); } + } else if (id == NotificationCenter.didCreatedNewDeleteTask) { + if (currentMessageObject == null || secretDeleteTimer == null) { + return; + } + SparseArray> mids = (SparseArray>)args[0]; + for(int i = 0; i < mids.size(); i++) { + int key = mids.keyAt(i); + ArrayList arr = mids.get(key); + for (Integer mid : arr) { + if (currentMessageObject.messageOwner.id == mid) { + currentMessageObject.messageOwner.destroyTime = key; + secretDeleteTimer.invalidate(); + return; + } + } + } } } @@ -157,9 +204,10 @@ public class SecretPhotoViewer implements NotificationCenter.NotificationCenterD } parentActivity = activity; - windowView = new FrameLayout(activity); + windowView = new FrameLayoutTouchListener(activity); windowView.setBackgroundColor(0xff000000); - windowView.setFocusable(false); + windowView.setFocusable(true); + windowView.setFocusableInTouchMode(true); containerView = new FrameLayoutDrawer(activity); containerView.setFocusable(false); @@ -169,13 +217,22 @@ public class SecretPhotoViewer implements NotificationCenter.NotificationCenterD layoutParams.height = FrameLayout.LayoutParams.MATCH_PARENT; layoutParams.gravity = Gravity.TOP | Gravity.LEFT; containerView.setLayoutParams(layoutParams); + containerView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_POINTER_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + closePhoto(); + } + return true; + } + }); secretDeleteTimer = new SecretDeleteTimer(activity); containerView.addView(secretDeleteTimer); layoutParams = (FrameLayout.LayoutParams)secretDeleteTimer.getLayoutParams(); layoutParams.gravity = Gravity.TOP | Gravity.RIGHT; layoutParams.width = AndroidUtilities.dp(100); - layoutParams.height = AndroidUtilities.dp(27); + layoutParams.height = AndroidUtilities.dp(32); layoutParams.rightMargin = AndroidUtilities.dp(19); layoutParams.topMargin = AndroidUtilities.dp(19); secretDeleteTimer.setLayoutParams(layoutParams); @@ -197,13 +254,34 @@ public class SecretPhotoViewer implements NotificationCenter.NotificationCenterD } NotificationCenter.getInstance().addObserver(this, NotificationCenter.messagesDeleted); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.didCreatedNewDeleteTask); TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(messageObject.messageOwner.media.photo.sizes, AndroidUtilities.getPhotoSize()); int size = sizeFull.size; if (size == 0) { size = -1; } - centerImage.setImage(sizeFull.location, null, null, size, false); + BitmapDrawable drawable = ImageLoader.getInstance().getImageFromMemory(sizeFull.location, null, null, null); + if (drawable == null) { + File file = FileLoader.getPathToAttach(sizeFull); + Bitmap bitmap = null; + try { + bitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); + } catch (Throwable e) { + ImageLoader.getInstance().clearMemory(); + bitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); + } + if (bitmap != null) { + drawable = new BitmapDrawable(bitmap); + ImageLoader.getInstance().putImageToCache(drawable, sizeFull.location.volume_id + "_" + sizeFull.location.local_id); + } + } + if (drawable != null) { + centerImage.setImageBitmap(drawable); + } else { + centerImage.setImage(sizeFull.location, null, null, size, false); + } + currentMessageObject = messageObject; AndroidUtilities.lockOrientation(parentActivity); @@ -220,16 +298,28 @@ public class SecretPhotoViewer implements NotificationCenter.NotificationCenterD WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE); wm.addView(windowView, windowLayoutParams); secretDeleteTimer.invalidate(); + isVisible = true; + } + + public boolean isVisible() { + return isVisible; } public void closePhoto() { NotificationCenter.getInstance().removeObserver(this, NotificationCenter.messagesDeleted); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didCreatedNewDeleteTask); if (parentActivity == null) { return; } currentMessageObject = null; + isVisible = false; AndroidUtilities.unlockOrientation(parentActivity); - centerImage.setImageBitmap((Bitmap)null); + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + centerImage.setImageBitmap((Bitmap)null); + } + }); try { if (windowView.getParent() != null) { WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE); @@ -242,6 +332,9 @@ public class SecretPhotoViewer implements NotificationCenter.NotificationCenterD public void destroyPhotoViewer() { NotificationCenter.getInstance().removeObserver(this, NotificationCenter.messagesDeleted); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didCreatedNewDeleteTask); + isVisible = false; + currentMessageObject = null; if (parentActivity == null || windowView == null) { return; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/LayoutListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/LayoutListView.java index fa037f10..a475bc3c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/LayoutListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/LayoutListView.java @@ -10,11 +10,17 @@ package org.telegram.ui.Views; import android.content.Context; import android.util.AttributeSet; +import android.view.MotionEvent; import android.view.View; import android.widget.ListView; public class LayoutListView extends ListView { + public static interface OnInterceptTouchEventListener { + public abstract boolean onInterceptTouchEvent(MotionEvent event); + } + + private OnInterceptTouchEventListener onInterceptTouchEventListener; private int height = -1; public LayoutListView(Context context) { @@ -29,6 +35,18 @@ public class LayoutListView extends ListView { super(context, attrs, defStyle); } + public void setOnInterceptTouchEventListener(OnInterceptTouchEventListener listener) { + onInterceptTouchEventListener = listener; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (onInterceptTouchEventListener != null) { + return onInterceptTouchEventListener.onInterceptTouchEvent(ev); + } + return super.onInterceptTouchEvent(ev); + } + @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { View v = getChildAt(getChildCount() - 1); diff --git a/TMessagesProj/src/main/res/drawable-hdpi/circle1.png b/TMessagesProj/src/main/res/drawable-hdpi/circle1.png new file mode 100755 index 0000000000000000000000000000000000000000..7587e047b4d6d05caeca421d1289768055d4bc56 GIT binary patch literal 1569 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWuD@%u1Od5hW46K32*3xq68pHF_1f1wh>l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|81#=KlDb#X~hD#E>34K5C;EJ)Q4 zN-fSWElLJPT$(b-ssbzLqSVBa{GyQj{2W*)24v)y zG%_=W>2=9ZF3nBND}m`vLFhHZsTY(KatnYqyQCInmZhe+73JqDfW2&$iQ6s4IL(9V zO~LIJ6P$YWfsWA!MJ!T8!-RmT2gHOYTObFX@Kf`Esl5o8tef(LTNxObrh2+KhE&|T zGV8pzw4=yzb?M2E`lm#Fec&&0TT6FVlZXoYZ~lsaFE92#*L|_}dXsMMLJ?uxEe{+6 zJ+p3$tO+yB`ttjR`KHLQ$#3$^KJWWrd19B<{hKo@joM-6+skmY@0BfcHy7s+?Bf3yze^eOKOGjhe-x{h+hUZ;Qqrwt9*CY#DR(n_9Z! zu56pWCrI?KLI_#hLAz#UhV){x~eF zufy-`?Hi-ktZ`5~@y|m22@hXnt=eS~_NKbFQG{LdvMIYvan6-3L>5=7ug+U;pOI&Q0Fd>v^o+ zgzxzH`yKoDtL$Djr{g7(9?aczdgH1%W~)nc8=mX_5faV&bNzSS!m!>RwJ-W+7q2xL z?q8<7E}mIsl~5hK@+rTA?uuHQ*J=H>YU0Xr@P8xo{Zs+-`=2+J0=Cx0UajmubpFP& zM@{>(1j5{YbLFg3i#ILsj{mmc%(nYa3MQJTR_;&#ydg|{Rczp-ih$7g?H4VVbIY}z jdu_H`tL3%Xb|xN%Us*Ld=S3j3^P6c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`f(~1RD^r68eAMwS&*t9 zlvv ztM~P_^2{qPNz6-5^>ndS0-B(gnVDi`ZeeO@=3-=O;^yLJXy|I<;pArS>TK*} zXyIxE)9aF-T$-DjR|3v4~Pj*wm=R%;iu*SQ+p9GS-%oci)3J6H1TwC45_%a zW!lEQ%+xH5w_zIJ)<(v-ZGA!5PmcXz@~rq;==eqs7~w(R5#natHM43E9xpI&*O z{9~N(Bc|mXuFsgid^&%krupY4uNUc)1h2RJV~@|e8r;f%YU$%mnr3(9wd^(ebzNWF c_@sS+VSiP)Xy?)pXHc2q>FVdQ&MBb@0BSR$VE_OC literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/circle1.png b/TMessagesProj/src/main/res/drawable-mdpi/circle1.png new file mode 100755 index 0000000000000000000000000000000000000000..1590ab4e2aa4a3fb92f3a5c81cc4bf7024c2238f GIT binary patch literal 1344 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWuD@%u1Od5hW46K32*3xq68pHF_1f1wh>l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|81#=KlDb#X~hD#E>34K5C;EJ)Q4 zN-fSWElLJPT$(b-ssbzLqSVBa{GyQj{2W*)24v)y2=9ZF3nBND}m`vLFhHcsTY(KatnYqyQCInmZhe+73JqDfW2&$iQ6p(IL(9V zO~LIJL!5f`fsWA!MJ!T8!-RmT2gHOYTObFX@Kf`Esl5o8tfv~zX<}et+~Vot7*cWT z$aG)t!wv#%+h4njRB!lpp-bWI!9^19S*r!>Tg<=iU-{tZ{RQkt@41|D)Vi@a>;t#f z#;or52V9(_4yomp#aCz~dOtr~R+hd@;fg7*)B?U$336vX+)}S#?q9%d^}ze7J2%(; zNCw>vjLSsM)-_8PFwWa7HG?I30jHXa8Ly-CoTm9EY%kW9JGj2MC~U!|f3bCkc{EFP zj??sK2dtjE+n;1$z02;pFn-FB><3~$3fVLcmN|MpQ8x-?zMddry5TI}=dg*7?_F-@ z$*m2ZA$(M;op;N>!Yi9Pl5*MDWFByRUetY7ky(3=%raNc`x9!m-wyK4+VghP3N6$7 z6`7%2lP*k?(bVbY;n6uJe`1GFX2ANC1?d+Z{EK?GE!C6U5uB@F+WqU8--MQVtjuu} zT9y>&DfnidF#PYe;k@{zO^VEK6RsZ?zc_QD@WsbwwQJO63THog7BSEM0Au~JvZHqL zr?1NR1YA&_Cn)s1$!`0((s$2GdDYr4K2Tc7zhv%?M_-qEtXm@ZckT2CDpnJgNcx?= zvt^fNdvJe$)U$^rYs%V>edg+azIoxtKe9G0$BLI~{nkFf5U?z8(t#Dnqd;Yvr>mdK II;Vst08B09nE(I) literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/circle1.png b/TMessagesProj/src/main/res/drawable-xhdpi/circle1.png new file mode 100755 index 0000000000000000000000000000000000000000..8ba4640c07375e889b890dead57014990dc94147 GIT binary patch literal 1815 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 w99bjWalg>q^rbqFbw Date: Sat, 11 Oct 2014 15:30:32 +0400 Subject: [PATCH 04/18] Stability improvements --- TMessagesProj/build.gradle | 2 +- .../telegram/android/AndroidUtilities.java | 32 ++++++++++++ .../org/telegram/android/MessagesStorage.java | 13 ++++- .../telegram/android/SendMessagesHelper.java | 20 +++---- .../android/VideoEncodingService.java | 2 +- .../org/telegram/messenger/Utilities.java | 31 ----------- .../java/org/telegram/ui/ChatActivity.java | 52 ++++++++++--------- .../java/org/telegram/ui/MediaActivity.java | 2 +- .../org/telegram/ui/PhotoPickerActivity.java | 2 +- .../ui/Views/ActionBar/ActionBarLayer.java | 4 +- .../ui/Views/ActionBar/BaseFragment.java | 6 ++- .../org/telegram/ui/Views/LayoutListView.java | 2 +- .../telegram/ui/Views/VideoTimelineView.java | 10 ++-- 13 files changed, 99 insertions(+), 79 deletions(-) diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index a0173758..7f216ab8 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -19,7 +19,7 @@ tasks.withType(JavaCompile) { dependencies { compile 'com.android.support:support-v4:20.0.+' compile 'com.google.android.gms:play-services:3.2.+' - compile 'net.hockeyapp.android:HockeySDK:3.0.1' + compile 'net.hockeyapp.android:HockeySDK:3.0.2' compile 'com.googlecode.mp4parser:isoparser:1.0.+' } diff --git a/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java index d96bd68d..8de3f997 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java @@ -9,6 +9,7 @@ package org.telegram.android; import android.app.Activity; +import android.app.ProgressDialog; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Configuration; @@ -32,6 +33,9 @@ import java.util.Hashtable; import java.util.Locale; public class AndroidUtilities { + + public static ProgressDialog progressDialog; + private static final Hashtable typefaceCache = new Hashtable(); private static int prevOrientation = -10; private static boolean waitingForSms = false; @@ -371,4 +375,32 @@ public class AndroidUtilities { } return photoSize; } + + public static void ShowProgressDialog(final Activity activity, final String message) { + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + if(activity != null && !activity.isFinishing()) { + progressDialog = new ProgressDialog(activity); + if (message != null) { + progressDialog.setMessage(message); + } + progressDialog.setCanceledOnTouchOutside(false); + progressDialog.setCancelable(false); + progressDialog.show(); + } + } + }); + } + + public static void HideProgressDialog() { + RunOnUIThread(new Runnable() { + @Override + public void run() { + if (progressDialog != null) { + progressDialog.dismiss(); + } + } + }); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java index 592b6e29..e47cb866 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java @@ -183,7 +183,8 @@ public class MessagesStorage { @Override public void run() { try { - if (currentVersion < 4) { + int version = currentVersion; + if (version < 4) { database.executeFast("CREATE TABLE IF NOT EXISTS user_photos(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS mid_idx_media ON media(mid);").stepThis().dispose(); @@ -254,8 +255,10 @@ public class MessagesStorage { } } }); + database.executeFast("PRAGMA user_version = 4").stepThis().dispose(); + version = 4; } - if (currentVersion < 6) { + if (version == 4 && version < 6) { database.executeFast("CREATE TABLE IF NOT EXISTS enc_tasks_v2(mid INTEGER PRIMARY KEY, date INTEGER)").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS date_idx_enc_tasks_v2 ON enc_tasks_v2(date);").stepThis().dispose(); database.beginTransaction(); @@ -284,6 +287,12 @@ public class MessagesStorage { database.executeFast("ALTER TABLE messages ADD COLUMN media INTEGER default 0").stepThis().dispose(); database.executeFast("PRAGMA user_version = 6").stepThis().dispose(); + version = 6; + } + if (version == 6 && version < 7) { + database.executeFast("ALTER TABLE enc_chats ADD COLUMN layer INTEGER default 0").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 6").stepThis().dispose(); + version = 7; } } catch (Exception e) { FileLog.e("tmessages", e); diff --git a/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java index ff2a5e90..63b2b1c1 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java @@ -326,23 +326,23 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } public void sendMessage(TLRPC.User user, long peer) { - sendMessage(null, 0, 0, null, null, null, user, null, null, null, peer, false, null); + sendMessage(null, null, null, null, null, null, user, null, null, null, peer, false, null); } public void sendMessage(MessageObject message) { - sendMessage(null, 0, 0, null, null, message, null, null, null, null, message.getDialogId(), true, message.messageOwner.attachPath); + sendMessage(null, null, null, null, null, message, null, null, null, null, message.getDialogId(), true, message.messageOwner.attachPath); } public void sendMessage(MessageObject message, long peer) { - sendMessage(null, 0, 0, null, null, message, null, null, null, null, peer, false, message.messageOwner.attachPath); + sendMessage(null, null, null, null, null, message, null, null, null, null, peer, false, message.messageOwner.attachPath); } public void sendMessage(TLRPC.TL_document document, String originalPath, String path, long peer) { - sendMessage(null, 0, 0, null, null, null, null, document, null, originalPath, peer, false, path); + sendMessage(null, null, null, null, null, null, null, document, null, originalPath, peer, false, path); } public void sendMessage(String message, long peer) { - sendMessage(message, 0, 0, null, null, null, null, null, null, null, peer, false, null); + sendMessage(message, null, null, null, null, null, null, null, null, null, peer, false, null); } public void sendMessage(double lat, double lon, long peer) { @@ -350,18 +350,18 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } public void sendMessage(TLRPC.TL_photo photo, String originalPath, long peer) { - sendMessage(null, 0, 0, photo, null, null, null, null, null, originalPath, peer, false, null); + sendMessage(null, null, null, photo, null, null, null, null, null, originalPath, peer, false, null); } public void sendMessage(TLRPC.TL_video video, String originalPath, String path, long peer) { - sendMessage(null, 0, 0, null, video, null, null, null, null, originalPath, peer, false, path); + sendMessage(null, null, null, null, video, null, null, null, null, originalPath, peer, false, path); } public void sendMessage(TLRPC.TL_audio audio, String path, long peer) { - sendMessage(null, 0, 0, null, null, null, null, null, audio, null, peer, false, path); + sendMessage(null, null, null, null, null, null, null, null, audio, null, peer, false, path); } - private int sendMessage(String message, double lat, double lon, TLRPC.TL_photo photo, TLRPC.TL_video video, MessageObject msgObj, TLRPC.User user, TLRPC.TL_document document, TLRPC.TL_audio audio, String originalPath, long peer, boolean retry, String path) { + private int sendMessage(String message, Double lat, Double lon, TLRPC.TL_photo photo, TLRPC.TL_video video, MessageObject msgObj, TLRPC.User user, TLRPC.TL_document document, TLRPC.TL_audio audio, String originalPath, long peer, boolean retry, String path) { TLRPC.Message newMsg = null; int type = -1; int lower_id = (int) peer; @@ -420,7 +420,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter newMsg.media = new TLRPC.TL_messageMediaEmpty(); type = 0; newMsg.message = message; - } else if (lat != 0 && lon != 0) { + } else if (lat != null && lon != null) { if (lower_id != 0) { newMsg = new TLRPC.TL_message(); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/android/VideoEncodingService.java b/TMessagesProj/src/main/java/org/telegram/android/VideoEncodingService.java index 17357053..e057c682 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/VideoEncodingService.java +++ b/TMessagesProj/src/main/java/org/telegram/android/VideoEncodingService.java @@ -45,7 +45,7 @@ public class VideoEncodingService extends Service implements NotificationCenter. public void didReceivedNotification(int id, Object... args) { if (id == NotificationCenter.FileUploadProgressChanged) { String fileName = (String)args[0]; - if (path.equals(fileName)) { + if (path != null && path.equals(fileName)) { Float progress = (Float) args[1]; Boolean enc = (Boolean) args[2]; currentProgress = (int)(progress * 100); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java index 998079ff..5fbf4226 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java @@ -9,7 +9,6 @@ package org.telegram.messenger; import android.app.Activity; -import android.app.ProgressDialog; import android.content.ContentUris; import android.content.Context; import android.content.Intent; @@ -73,8 +72,6 @@ public class Utilities { final protected static char[] hexArray = "0123456789ABCDEF".toCharArray(); - public static ProgressDialog progressDialog; - static { try { File URANDOM_FILE = new File("/dev/urandom"); @@ -426,34 +423,6 @@ public class Utilities { return packedData; } - public static void ShowProgressDialog(final Activity activity, final String message) { - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - if(!activity.isFinishing()) { - progressDialog = new ProgressDialog(activity); - if (message != null) { - progressDialog.setMessage(message); - } - progressDialog.setCanceledOnTouchOutside(false); - progressDialog.setCancelable(false); - progressDialog.show(); - } - } - }); - } - - public static void HideProgressDialog(Activity activity) { - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - if (progressDialog != null) { - progressDialog.dismiss(); - } - } - }); - } - public static boolean copyFile(InputStream sourceFile, File destFile) throws IOException { OutputStream out = new FileOutputStream(destFile); byte[] buf = new byte[4096]; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 16284f91..5d913818 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -834,35 +834,37 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatListView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_POINTER_UP) { - if (openSecretPhotoRunnable != null) { - AndroidUtilities.CancelRunOnUIThread(openSecretPhotoRunnable); - openSecretPhotoRunnable = null; - } else { - if (SecretPhotoViewer.getInstance().isVisible()) { - AndroidUtilities.RunOnUIThread(new Runnable() { - @Override - public void run() { - chatListView.setOnItemLongClickListener(onItemLongClickListener); - chatListView.setOnItemClickListener(onItemClickListener); - chatListView.setLongClickable(true); - } - }); - SecretPhotoViewer.getInstance().closePhoto(); + if (openSecretPhotoRunnable != null || SecretPhotoViewer.getInstance().isVisible()) { + if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_POINTER_UP) { + if (openSecretPhotoRunnable != null) { + AndroidUtilities.CancelRunOnUIThread(openSecretPhotoRunnable); + openSecretPhotoRunnable = null; + } else { + if (SecretPhotoViewer.getInstance().isVisible()) { + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + chatListView.setOnItemLongClickListener(onItemLongClickListener); + chatListView.setOnItemClickListener(onItemClickListener); + chatListView.setLongClickable(true); + } + }); + SecretPhotoViewer.getInstance().closePhoto(); + } } - } - } else if (event.getAction() != MotionEvent.ACTION_DOWN) { - if (SecretPhotoViewer.getInstance().isVisible()) { - return true; - } else if (openSecretPhotoRunnable != null) { - if (event.getAction() == MotionEvent.ACTION_MOVE) { - if (Math.hypot(startX - event.getX(), startY - event.getY()) > AndroidUtilities.dp(5)) { + } else if (event.getAction() != MotionEvent.ACTION_DOWN) { + if (SecretPhotoViewer.getInstance().isVisible()) { + return true; + } else if (openSecretPhotoRunnable != null) { + if (event.getAction() == MotionEvent.ACTION_MOVE) { + if (Math.hypot(startX - event.getX(), startY - event.getY()) > AndroidUtilities.dp(5)) { + AndroidUtilities.CancelRunOnUIThread(openSecretPhotoRunnable); + openSecretPhotoRunnable = null; + } + } else { AndroidUtilities.CancelRunOnUIThread(openSecretPhotoRunnable); openSecretPhotoRunnable = null; } - } else { - AndroidUtilities.CancelRunOnUIThread(openSecretPhotoRunnable); - openSecretPhotoRunnable = null; } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java index 5118653f..0eb4b6c5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java @@ -94,7 +94,7 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No @Override public void onItemClick(int id) { if (id == -1) { - if (Build.VERSION.SDK_INT < 11) { + if (Build.VERSION.SDK_INT < 11 && listView != null) { listView.setAdapter(null); listView = null; listAdapter = null; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerActivity.java index f9ce3165..351d86b3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerActivity.java @@ -341,7 +341,7 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen @Override public void sendButtonPressed(int index) { if (selectedPhotos.isEmpty()) { - if (index < 0 || index >= selectedAlbum.photos.size()) { + if (selectedAlbum == null || index < 0 || index >= selectedAlbum.photos.size()) { return; } MediaController.PhotoEntry photoEntry = selectedAlbum.photos.get(index); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBarLayer.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBarLayer.java index 0528a8cc..1dfef5f5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBarLayer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBarLayer.java @@ -171,9 +171,9 @@ public class ActionBarLayer extends FrameLayout { x = AndroidUtilities.dp(16 + leftMargin); } else { if (!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { - x = AndroidUtilities.dp(22 + leftMargin) + (int)(logoImageView.getDrawable().getIntrinsicWidth() / 1.3f); + x = AndroidUtilities.dp(22 + leftMargin) + (logoImageView.getDrawable() != null ? (int)(logoImageView.getDrawable().getIntrinsicWidth() / 1.3f) : 0); } else { - x = AndroidUtilities.dp(22 + leftMargin) + logoImageView.getDrawable().getIntrinsicWidth(); + x = AndroidUtilities.dp(22 + leftMargin) + (logoImageView.getDrawable() != null ? logoImageView.getDrawable().getIntrinsicWidth() : 0); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/BaseFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/BaseFragment.java index c18ca4f9..51e4b430 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/BaseFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/BaseFragment.java @@ -54,7 +54,11 @@ public class BaseFragment { if (fragmentView != null) { ViewGroup parent = (ViewGroup) fragmentView.getParent(); if (parent != null) { - parent.removeView(fragmentView); + try { + parent.removeView(fragmentView); + } catch (Exception e) { + FileLog.e("tmessages", e); + } } fragmentView = null; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/LayoutListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/LayoutListView.java index a475bc3c..4d5617a8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/LayoutListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/LayoutListView.java @@ -42,7 +42,7 @@ public class LayoutListView extends ListView { @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (onInterceptTouchEventListener != null) { - return onInterceptTouchEventListener.onInterceptTouchEvent(ev); + return onInterceptTouchEventListener.onInterceptTouchEvent(ev) || super.onInterceptTouchEvent(ev); } return super.onInterceptTouchEvent(ev); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/VideoTimelineView.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/VideoTimelineView.java index 92e2ef3a..451a7e14 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/VideoTimelineView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/VideoTimelineView.java @@ -153,9 +153,13 @@ public class VideoTimelineView extends View { public void setVideoPath(String path) { mediaMetadataRetriever = new MediaMetadataRetriever(); - mediaMetadataRetriever.setDataSource(path); - String duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); - videoLength = Long.parseLong(duration); + try { + mediaMetadataRetriever.setDataSource(path); + String duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); + videoLength = Long.parseLong(duration); + } catch (Exception e) { + FileLog.e("tmessages", e); + } } public void setDelegate(VideoTimelineViewDelegate delegate) { From b2ad802ba56ab67f90697b1988cff7ef6e1ad9af Mon Sep 17 00:00:00 2001 From: DrKLO Date: Tue, 14 Oct 2014 12:13:16 +0400 Subject: [PATCH 05/18] Update secret chats layer --- .../telegram/android/AndroidUtilities.java | 47 ++-- .../org/telegram/android/MessageObject.java | 2 +- .../telegram/android/MessagesController.java | 63 +++++- .../org/telegram/android/MessagesStorage.java | 69 ++++-- .../telegram/android/SendMessagesHelper.java | 208 +++++++++++++----- .../org/telegram/messenger/DispatchQueue.java | 2 +- .../java/org/telegram/messenger/TLRPC.java | 48 ++-- .../java/org/telegram/ui/LoginActivity.java | 9 +- 8 files changed, 295 insertions(+), 153 deletions(-) diff --git a/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java index 8de3f997..3c2dda04 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java @@ -9,7 +9,6 @@ package org.telegram.android; import android.app.Activity; -import android.app.ProgressDialog; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Configuration; @@ -34,8 +33,6 @@ import java.util.Locale; public class AndroidUtilities { - public static ProgressDialog progressDialog; - private static final Hashtable typefaceCache = new Hashtable(); private static int prevOrientation = -10; private static boolean waitingForSms = false; @@ -266,6 +263,22 @@ public class AndroidUtilities { return 0x0000000100000000L | ((long)id & 0x00000000FFFFFFFFL); } + public static int getMyLayerVersion(int layer) { + return layer & 0xffff; + } + + public static int getPeerLayerVersion(int layer) { + return (layer >> 16) & 0xffff; + } + + public static int setMyLayerVersion(int layer, int version) { + return layer & 0xffff0000 | version; + } + + public static int setPeerLayerVersion(int layer, int version) { + return layer & 0x0000ffff | (version << 16); + } + public static void RunOnUIThread(Runnable runnable) { RunOnUIThread(runnable, 0); } @@ -375,32 +388,4 @@ public class AndroidUtilities { } return photoSize; } - - public static void ShowProgressDialog(final Activity activity, final String message) { - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - if(activity != null && !activity.isFinishing()) { - progressDialog = new ProgressDialog(activity); - if (message != null) { - progressDialog.setMessage(message); - } - progressDialog.setCanceledOnTouchOutside(false); - progressDialog.setCancelable(false); - progressDialog.show(); - } - } - }); - } - - public static void HideProgressDialog() { - RunOnUIThread(new Runnable() { - @Override - public void run() { - if (progressDialog != null) { - progressDialog.dismiss(); - } - } - }); - } } diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java index f01e0b35..20c7c11b 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java @@ -616,7 +616,7 @@ public class MessageObject { } public boolean isSecretMedia() { - return messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && messageOwner.ttl != 0 && messageOwner.ttl <= 60; + return messageOwner instanceof TLRPC.TL_message_secret && messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && messageOwner.ttl != 0 && messageOwner.ttl <= 60; } public static void setIsUnread(TLRPC.Message message, boolean unread) { diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java index da42b019..f2ee4c2f 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java @@ -71,6 +71,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter private boolean gettingNewDeleteTask = false; private int currentDeletingTaskTime = 0; private ArrayList currentDeletingTaskMids = null; + private Runnable currentDeleteTaskRunnable = null; public int totalDialogsCount = 0; public boolean loadingDialogs = false; @@ -336,6 +337,12 @@ public class MessagesController implements NotificationCenter.NotificationCenter startingSecretChat = false; statusRequest = 0; statusSettingState = 0; + + if (currentDeleteTaskRunnable != null) { + Utilities.stageQueue.cancelRunnable(currentDeleteTaskRunnable); + currentDeleteTaskRunnable = null; + } + addSupportUser(); } @@ -530,11 +537,15 @@ public class MessagesController implements NotificationCenter.NotificationCenter }); } - private void checkDeletingTask() { + private boolean checkDeletingTask(boolean runnable) { int currentServerTime = ConnectionsManager.getInstance().getCurrentTime(); - if (currentDeletingTaskMids != null && currentDeletingTaskTime != 0 && currentDeletingTaskTime <= currentServerTime) { + if (currentDeletingTaskMids != null && (runnable || currentDeletingTaskTime != 0 && currentDeletingTaskTime <= currentServerTime)) { currentDeletingTaskTime = 0; + if (currentDeleteTaskRunnable != null && !runnable) { + Utilities.stageQueue.cancelRunnable(currentDeleteTaskRunnable); + } + currentDeleteTaskRunnable = null; AndroidUtilities.RunOnUIThread(new Runnable() { @Override public void run() { @@ -550,7 +561,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter }); } }); + return true; } + return false; } public void processLoadedDeleteTask(final int taskTime, final ArrayList messages) { @@ -562,7 +575,21 @@ public class MessagesController implements NotificationCenter.NotificationCenter currentDeletingTaskTime = taskTime; currentDeletingTaskMids = messages; - checkDeletingTask(); + if (currentDeleteTaskRunnable != null) { + Utilities.stageQueue.cancelRunnable(currentDeleteTaskRunnable); + currentDeleteTaskRunnable = null; + } + + if (!checkDeletingTask(false)) { + currentDeleteTaskRunnable = new Runnable() { + @Override + public void run() { + checkDeletingTask(true); + } + }; + int currentServerTime = ConnectionsManager.getInstance().getCurrentTime(); + Utilities.stageQueue.postRunnable(currentDeleteTaskRunnable, (long)Math.abs(currentServerTime - currentDeletingTaskTime) * 1000); + } } else { currentDeletingTaskTime = 0; currentDeletingTaskMids = null; @@ -1069,7 +1096,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter public void updateTimerProc() { long currentTime = System.currentTimeMillis(); - checkDeletingTask(); + checkDeletingTask(false); if (UserConfig.isClientActivated()) { if (ConnectionsManager.getInstance().getPauseTime() == 0 && ApplicationLoader.isScreenOn && !ApplicationLoader.mainInterfacePaused) { @@ -3499,7 +3526,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } public TLRPC.Message decryptMessage(TLRPC.EncryptedMessage message) { - TLRPC.EncryptedChat chat = getEncryptedChatDB(message.chat_id); + final TLRPC.EncryptedChat chat = getEncryptedChatDB(message.chat_id); if (chat == null) { return null; } @@ -3522,9 +3549,18 @@ public class MessagesController implements NotificationCenter.NotificationCenter from_id = chat.participant_id; } + if (object instanceof TLRPC.TL_decryptedMessageLayer) { + object = ((TLRPC.TL_decryptedMessageLayer) object).message; + } + if (object instanceof TLRPC.TL_decryptedMessage) { TLRPC.TL_decryptedMessage decryptedMessage = (TLRPC.TL_decryptedMessage)object; - TLRPC.TL_message_secret newMessage = new TLRPC.TL_message_secret(); + TLRPC.TL_message newMessage = null; + if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 17) { + newMessage = new TLRPC.TL_message_secret(); + } else { + newMessage = new TLRPC.TL_message(); + } newMessage.message = decryptedMessage.message; newMessage.date = message.date; newMessage.local_id = newMessage.id = UserConfig.getNewMessageId(); @@ -3666,7 +3702,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } return newMessage; } else if (object instanceof TLRPC.TL_decryptedMessageService) { - TLRPC.TL_decryptedMessageService serviceMessage = (TLRPC.TL_decryptedMessageService)object; + final TLRPC.TL_decryptedMessageService serviceMessage = (TLRPC.TL_decryptedMessageService)object; if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL || serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages) { TLRPC.TL_messageService newMessage = new TLRPC.TL_messageService(); if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { @@ -3727,6 +3763,19 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (!serviceMessage.action.random_ids.isEmpty()) { MessagesStorage.getInstance().createTaskForSecretChat(chat.id, 0, message.date, 1, serviceMessage.action.random_ids); } + } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionNotifyLayer) { + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + int currentPeerLayer = AndroidUtilities.getPeerLayerVersion(chat.layer); + chat.layer = 0; + chat.layer = AndroidUtilities.setPeerLayerVersion(chat.layer, serviceMessage.action.layer); + MessagesStorage.getInstance().updateEncryptedChatLayer(chat); + if (currentPeerLayer < 17) { + SendMessagesHelper.getInstance().sendNotifyLayerMessage(chat); + } + } + }); } else { return null; } diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java index e47cb866..ff3b6c2d 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java @@ -93,7 +93,7 @@ public class MessagesStorage { database.executeFast("CREATE TABLE users(uid INTEGER PRIMARY KEY, name TEXT, status INTEGER, data BLOB)").stepThis().dispose(); database.executeFast("CREATE TABLE messages(mid INTEGER PRIMARY KEY, uid INTEGER, read_state INTEGER, send_state INTEGER, date INTEGER, data BLOB, out INTEGER, ttl INTEGER, media INTEGER)").stepThis().dispose(); database.executeFast("CREATE TABLE chats(uid INTEGER PRIMARY KEY, name TEXT, data BLOB)").stepThis().dispose(); - database.executeFast("CREATE TABLE enc_chats(uid INTEGER PRIMARY KEY, user INTEGER, name TEXT, data BLOB, g BLOB, authkey BLOB, ttl INTEGER)").stepThis().dispose(); + database.executeFast("CREATE TABLE enc_chats(uid INTEGER PRIMARY KEY, user INTEGER, name TEXT, data BLOB, g BLOB, authkey BLOB, ttl INTEGER, layer INTEGER)").stepThis().dispose(); database.executeFast("CREATE TABLE dialogs(did INTEGER PRIMARY KEY, date INTEGER, unread_count INTEGER, last_mid INTEGER)").stepThis().dispose(); database.executeFast("CREATE TABLE chat_settings(uid INTEGER PRIMARY KEY, participants BLOB)").stepThis().dispose(); database.executeFast("CREATE TABLE contacts(uid INTEGER PRIMARY KEY, mutual INTEGER)").stepThis().dispose(); @@ -136,7 +136,7 @@ public class MessagesStorage { database.executeFast("CREATE INDEX IF NOT EXISTS mid_out_idx_messages ON messages(mid, out);").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS task_idx_messages ON messages(uid, out, read_state, ttl, date, send_state);").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS send_state_idx_messages ON messages(mid, send_state, date) WHERE mid < 0 AND send_state = 1;").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 6").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 7").stepThis().dispose(); } else { try { SQLiteCursor cursor = database.queryFinalized("SELECT seq, pts, date, qts, lsv, sg, pbytes FROM params WHERE id = 1"); @@ -168,7 +168,7 @@ public class MessagesStorage { } int version = database.executeInt("PRAGMA user_version"); - if (version < 6) { + if (version < 7) { updateDbToLastVersion(version); } } @@ -291,7 +291,7 @@ public class MessagesStorage { } if (version == 6 && version < 7) { database.executeFast("ALTER TABLE enc_chats ADD COLUMN layer INTEGER default 0").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 6").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 7").stepThis().dispose(); version = 7; } } catch (Exception e) { @@ -491,7 +491,7 @@ public class MessagesStorage { if (!encryptedChatIds.isEmpty()) { String stringToLoad = TextUtils.join(",", encryptedChatIds); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl FROM enc_chats WHERE uid IN(%s)", stringToLoad)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer FROM enc_chats WHERE uid IN(%s)", stringToLoad)); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { @@ -504,6 +504,7 @@ public class MessagesStorage { chat.a_or_b = cursor.byteArrayValue(2); chat.auth_key = cursor.byteArrayValue(3); chat.ttl = cursor.intValue(4); + chat.layer = cursor.intValue(5); } buffersStorage.reuseFreeBuffer(data); } @@ -1231,7 +1232,7 @@ public class MessagesStorage { cursor.dispose(); if (needEncrypted) { - cursor = database.queryFinalized("SELECT q.data, q.name, q.user, q.g, q.authkey, q.ttl, u.data, u.status FROM enc_chats as q INNER JOIN dialogs as d ON (q.uid << 32) = d.did INNER JOIN users as u ON q.user = u.uid"); + cursor = database.queryFinalized("SELECT q.data, u.name, q.user, q.g, q.authkey, q.ttl, u.data, u.status, q.layer FROM enc_chats as q INNER JOIN dialogs as d ON (q.uid << 32) = d.did INNER JOIN users as u ON q.user = u.uid"); while (cursor.next()) { String name = cursor.stringValue(1); if (name.startsWith(q) || name.contains(" " + q)) { @@ -1243,6 +1244,7 @@ public class MessagesStorage { chat.a_or_b = cursor.byteArrayValue(3); chat.auth_key = cursor.byteArrayValue(4); chat.ttl = cursor.intValue(5); + chat.layer = cursor.intValue(8); TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data2, data2.readInt32()); if (user.status != null) { @@ -1718,7 +1720,7 @@ public class MessagesStorage { if (!encryptedChatIds.isEmpty()) { String stringToLoad = TextUtils.join(",", encryptedChatIds); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl FROM enc_chats WHERE uid IN(%s)", stringToLoad)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer FROM enc_chats WHERE uid IN(%s)", stringToLoad)); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { @@ -1731,6 +1733,7 @@ public class MessagesStorage { chat.a_or_b = cursor.byteArrayValue(2); chat.auth_key = cursor.byteArrayValue(3); chat.ttl = cursor.intValue(4); + chat.layer = cursor.intValue(5); } buffersStorage.reuseFreeBuffer(data); } @@ -2147,6 +2150,30 @@ public class MessagesStorage { }); } + public void updateEncryptedChatLayer(final TLRPC.EncryptedChat chat) { + if (chat == null) { + return; + } + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + SQLitePreparedStatement state = null; + try { + state = database.executeFast("UPDATE enc_chats SET layer = ? WHERE uid = ?"); + state.bindInteger(1, chat.layer); + state.bindInteger(2, chat.id); + state.step(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (state != null) { + state.dispose(); + } + } + } + }); + } + public void updateEncryptedChat(final TLRPC.EncryptedChat chat) { if (chat == null) { return; @@ -2156,7 +2183,7 @@ public class MessagesStorage { public void run() { SQLitePreparedStatement state = null; try { - state = database.executeFast("UPDATE enc_chats SET data = ?, g = ?, authkey = ?, ttl = ? WHERE uid = ?"); + state = database.executeFast("UPDATE enc_chats SET data = ?, g = ?, authkey = ?, ttl = ?, layer = ? WHERE uid = ?"); ByteBufferDesc data = buffersStorage.getFreeBuffer(chat.getObjectSize()); ByteBufferDesc data2 = buffersStorage.getFreeBuffer(chat.a_or_b != null ? chat.a_or_b.length : 1); ByteBufferDesc data3 = buffersStorage.getFreeBuffer(chat.auth_key != null ? chat.auth_key.length : 1); @@ -2172,6 +2199,7 @@ public class MessagesStorage { state.bindByteBuffer(3, data3.buffer); state.bindInteger(4, chat.ttl); state.bindInteger(5, chat.id); + state.bindInteger(6, chat.layer); state.step(); buffersStorage.reuseFreeBuffer(data); buffersStorage.reuseFreeBuffer(data2); @@ -2196,7 +2224,7 @@ public class MessagesStorage { public void run() { try { int userToLoad = 0; - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl FROM enc_chats WHERE uid = %d", chat_id)); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer FROM enc_chats WHERE uid = %d", chat_id)); if (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { @@ -2207,6 +2235,7 @@ public class MessagesStorage { chat.a_or_b = cursor.byteArrayValue(2); chat.auth_key = cursor.byteArrayValue(3); chat.ttl = cursor.intValue(4); + chat.layer = cursor.intValue(5); } buffersStorage.reuseFreeBuffer(data); } @@ -2247,7 +2276,7 @@ public class MessagesStorage { @Override public void run() { try { - SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_chats VALUES(?, ?, ?, ?, ?, ?, ?)"); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_chats VALUES(?, ?, ?, ?, ?, ?, ?, ?)"); ByteBufferDesc data = buffersStorage.getFreeBuffer(chat.getObjectSize()); ByteBufferDesc data2 = buffersStorage.getFreeBuffer(chat.a_or_b != null ? chat.a_or_b.length : 1); ByteBufferDesc data3 = buffersStorage.getFreeBuffer(chat.auth_key != null ? chat.auth_key.length : 1); @@ -2271,6 +2300,7 @@ public class MessagesStorage { state.bindByteBuffer(5, data2.buffer); state.bindByteBuffer(6, data3.buffer); state.bindInteger(7, chat.ttl); + state.bindInteger(8, chat.layer); state.step(); state.dispose(); buffersStorage.reuseFreeBuffer(data); @@ -2441,7 +2471,7 @@ public class MessagesStorage { } private int getMessageMediaType(TLRPC.Message message) { - if (message.media instanceof TLRPC.TL_messageMediaPhoto && message.ttl != 0 && message.ttl <= 60) { + if (message instanceof TLRPC.TL_message_secret && message.media instanceof TLRPC.TL_messageMediaPhoto && message.ttl != 0 && message.ttl <= 60) { return 1; } return 0; @@ -2482,7 +2512,7 @@ public class MessagesStorage { messagesIdsMap.put(message.id, dialog_id); } - if (message.media instanceof TLRPC.TL_messageMediaVideo || message.media instanceof TLRPC.TL_messageMediaPhoto && (message.ttl == 0 || message.ttl > 60)) { + if (getMessageMediaType(message) == 0) { if (messageMediaIds.length() > 0) { messageMediaIds.append(","); } @@ -2566,7 +2596,7 @@ public class MessagesStorage { state3.step(); } - if (message.media instanceof TLRPC.TL_messageMediaVideo || message.media instanceof TLRPC.TL_messageMediaPhoto && (message.ttl == 0 || message.ttl > 60)) { + if (getMessageMediaType(message) == 0) { state2.requery(); state2.bindInteger(1, messageId); state2.bindLong(2, dialog_id); @@ -3128,7 +3158,7 @@ public class MessagesStorage { if (!encryptedToLoad.isEmpty()) { String toLoad = TextUtils.join(",", encryptedToLoad); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl FROM enc_chats WHERE uid IN(%s)", toLoad)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer FROM enc_chats WHERE uid IN(%s)", toLoad)); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { @@ -3141,6 +3171,7 @@ public class MessagesStorage { chat.a_or_b = cursor.byteArrayValue(2); chat.auth_key = cursor.byteArrayValue(3); chat.ttl = cursor.intValue(4); + chat.layer = cursor.intValue(5); } buffersStorage.reuseFreeBuffer(data); } @@ -3242,7 +3273,7 @@ public class MessagesStorage { state.bindByteBuffer(6, data.buffer); state.bindInteger(7, (MessageObject.isOut(message) ? 1 : 0)); state.bindInteger(8, 0); - state.bindInteger(9, getMessageMediaType(message)); + state.bindInteger(9, 0); state.step(); if (message.media instanceof TLRPC.TL_messageMediaVideo || message.media instanceof TLRPC.TL_messageMediaPhoto) { @@ -3384,7 +3415,7 @@ public class MessagesStorage { if (!encryptedToLoad.isEmpty()) { String toLoad = TextUtils.join(",", encryptedToLoad); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl FROM enc_chats WHERE uid IN(%s)", toLoad)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer FROM enc_chats WHERE uid IN(%s)", toLoad)); while (cursor.next()) { try { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); @@ -3399,6 +3430,7 @@ public class MessagesStorage { chat.a_or_b = cursor.byteArrayValue(2); chat.auth_key = cursor.byteArrayValue(3); chat.ttl = cursor.intValue(4); + chat.layer = cursor.intValue(5); } } buffersStorage.reuseFreeBuffer(data); @@ -3509,7 +3541,7 @@ public class MessagesStorage { state.bindByteBuffer(6, data.buffer); state.bindInteger(7, (MessageObject.isOut(message) ? 1 : 0)); state.bindInteger(8, 0); - state.bindInteger(9, getMessageMediaType(message)); + state.bindInteger(9, 0); state.step(); state2.bindLong(1, uid); @@ -3672,7 +3704,7 @@ public class MessagesStorage { public TLRPC.EncryptedChat getEncryptedChat(final int chat_id) { TLRPC.EncryptedChat chat = null; try { - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl FROM enc_chats WHERE uid = %d", chat_id)); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer FROM enc_chats WHERE uid = %d", chat_id)); if (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { @@ -3682,6 +3714,7 @@ public class MessagesStorage { chat.a_or_b = cursor.byteArrayValue(2); chat.auth_key = cursor.byteArrayValue(3); chat.ttl = cursor.intValue(4); + chat.layer = cursor.intValue(5); } } buffersStorage.reuseFreeBuffer(data); diff --git a/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java index 63b2b1c1..f8fb052b 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java @@ -29,9 +29,12 @@ import java.util.HashMap; public class SendMessagesHelper implements NotificationCenter.NotificationCenterDelegate { + public static final int CURRENT_SECRET_CHAT_LAYER = 17; + private TLRPC.ChatParticipants currentChatInfo = null; private HashMap> delayedMessages = new HashMap>(); private HashMap unsentMessages = new HashMap(); + private ArrayList sendingNotifyLayer = new ArrayList(); private class DelayedMessage { public TLObject sendRequest; @@ -70,6 +73,8 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter public void cleanUp() { delayedMessages.clear(); + sendingNotifyLayer.clear(); + unsentMessages.clear(); currentChatInfo = null; } @@ -135,7 +140,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } else if (encryptedFile != null && message.sendEncryptedRequest != null) { message.sendEncryptedRequest.media.key = encryptedFile.key; message.sendEncryptedRequest.media.iv = encryptedFile.iv; - performSendEncryptedRequest(message.sendEncryptedRequest, message.obj, message.encryptedChat, encryptedFile, message.originalPath); + performSendEncryptedRequest(message.sendEncryptedRequest, message.obj, message.encryptedChat, encryptedFile, message.originalPath, null); arr.remove(a); a--; } @@ -366,6 +371,12 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter int type = -1; int lower_id = (int) peer; int high_id = (int) (peer >> 32); + TLRPC.EncryptedChat encryptedChat = null; + TLRPC.InputPeer sendToPeer = null; + ArrayList sendToPeers = null; + if (lower_id == 0) { + encryptedChat = MessagesController.getInstance().getEncryptedChat(high_id); + } if (retry) { newMsg = msgObj.messageOwner; @@ -412,19 +423,19 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } } else { if (message != null) { - if (lower_id != 0) { - newMsg = new TLRPC.TL_message(); - } else { + if (encryptedChat != null && AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { newMsg = new TLRPC.TL_message_secret(); + } else { + newMsg = new TLRPC.TL_message(); } newMsg.media = new TLRPC.TL_messageMediaEmpty(); type = 0; newMsg.message = message; } else if (lat != null && lon != null) { - if (lower_id != 0) { - newMsg = new TLRPC.TL_message(); - } else { + if (encryptedChat != null && AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { newMsg = new TLRPC.TL_message_secret(); + } else { + newMsg = new TLRPC.TL_message(); } newMsg.media = new TLRPC.TL_messageMediaGeo(); newMsg.media.geo = new TLRPC.TL_geoPoint(); @@ -433,10 +444,10 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter newMsg.message = ""; type = 1; } else if (photo != null) { - if (lower_id != 0) { - newMsg = new TLRPC.TL_message(); - } else { + if (encryptedChat != null && AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { newMsg = new TLRPC.TL_message_secret(); + } else { + newMsg = new TLRPC.TL_message(); } newMsg.media = new TLRPC.TL_messageMediaPhoto(); newMsg.media.photo = photo; @@ -445,10 +456,10 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter TLRPC.FileLocation location1 = photo.sizes.get(photo.sizes.size() - 1).location; newMsg.attachPath = FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE) + "/" + location1.volume_id + "_" + location1.local_id + ".jpg"; } else if (video != null) { - if (lower_id != 0) { - newMsg = new TLRPC.TL_message(); - } else { + if (encryptedChat != null && AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { newMsg = new TLRPC.TL_message_secret(); + } else { + newMsg = new TLRPC.TL_message(); } newMsg.media = new TLRPC.TL_messageMediaVideo(); newMsg.media.video = video; @@ -480,10 +491,10 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter type = 4; } } else if (user != null) { - if (lower_id != 0) { - newMsg = new TLRPC.TL_message(); - } else { + if (encryptedChat != null && AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { newMsg = new TLRPC.TL_message_secret(); + } else { + newMsg = new TLRPC.TL_message(); } newMsg.media = new TLRPC.TL_messageMediaContact(); newMsg.media.phone_number = user.phone; @@ -493,10 +504,10 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter newMsg.message = ""; type = 6; } else if (document != null) { - if (lower_id != 0) { - newMsg = new TLRPC.TL_message(); - } else { + if (encryptedChat != null && AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { newMsg = new TLRPC.TL_message_secret(); + } else { + newMsg = new TLRPC.TL_message(); } newMsg.media = new TLRPC.TL_messageMediaDocument(); newMsg.media.document = document; @@ -504,10 +515,10 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter newMsg.message = "-1"; newMsg.attachPath = path; } else if (audio != null) { - if (lower_id != 0) { - newMsg = new TLRPC.TL_message(); - } else { + if (encryptedChat != null && AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { newMsg = new TLRPC.TL_message_secret(); + } else { + newMsg = new TLRPC.TL_message(); } newMsg.media = new TLRPC.TL_messageMediaAudio(); newMsg.media.audio = audio; @@ -526,9 +537,6 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter newMsg.date = ConnectionsManager.getInstance().getCurrentTime(); newMsg.flags |= TLRPC.MESSAGE_FLAG_UNREAD; newMsg.dialog_id = peer; - TLRPC.EncryptedChat encryptedChat = null; - TLRPC.InputPeer sendToPeer = null; - ArrayList sendToPeers = null; if (lower_id != 0) { if (high_id == 1) { if (currentChatInfo == null) { @@ -571,7 +579,6 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } } } else { - encryptedChat = MessagesController.getInstance().getEncryptedChat(high_id); newMsg.to_id = new TLRPC.TL_peerUser(); if (encryptedChat.participant_id == UserConfig.getClientUserId()) { newMsg.to_id.user_id = encryptedChat.admin_id; @@ -581,7 +588,6 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter newMsg.ttl = encryptedChat.ttl; } - MessageObject newMsgObj = new MessageObject(newMsg, null, 2); newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING; @@ -616,7 +622,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter Utilities.random.nextBytes(reqSend.random_bytes); reqSend.message = message; reqSend.media = new TLRPC.TL_decryptedMessageMediaEmpty(); - performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null, null); + performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null, null, null); } } else if (type >= 1 && type <= 3 || type >= 5 && type <= 8) { if (encryptedChat == null) { @@ -771,7 +777,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter reqSend.media = new TLRPC.TL_decryptedMessageMediaGeoPoint(); reqSend.media.lat = lat; reqSend.media._long = lon; - performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null, null); + performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null, null, null); } else if (type == 2) { TLRPC.PhotoSize small = photo.sizes.get(0); TLRPC.PhotoSize big = photo.sizes.get(photo.sizes.size() - 1); @@ -797,10 +803,14 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter encryptedFile.access_hash = big.location.secret; reqSend.media.key = big.location.key; reqSend.media.iv = big.location.iv; - performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, encryptedFile, null); + performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, encryptedFile, null, null); } } else if (type == 3) { - reqSend.media = new TLRPC.TL_decryptedMessageMediaVideo_old(); + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend.media = new TLRPC.TL_decryptedMessageMediaVideo(); + } else { + reqSend.media = new TLRPC.TL_decryptedMessageMediaVideo_old(); + } reqSend.media.duration = video.duration; reqSend.media.size = video.size; reqSend.media.w = video.w; @@ -824,7 +834,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter encryptedFile.access_hash = video.access_hash; reqSend.media.key = video.key; reqSend.media.iv = video.iv; - performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, encryptedFile, null); + performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, encryptedFile, null, null); } } else if (type == 6) { reqSend.media = new TLRPC.TL_decryptedMessageMediaContact(); @@ -832,7 +842,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter reqSend.media.first_name = user.first_name; reqSend.media.last_name = user.last_name; reqSend.media.user_id = user.id; - performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null, null); + performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null, null, null); } else if (type == 7) { reqSend.media = new TLRPC.TL_decryptedMessageMediaDocument(); reqSend.media.size = document.size; @@ -862,10 +872,14 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter encryptedFile.access_hash = document.access_hash; reqSend.media.key = document.key; reqSend.media.iv = document.iv; - performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, encryptedFile, null); + performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, encryptedFile, null, null); } } else if (type == 8) { - reqSend.media = new TLRPC.TL_decryptedMessageMediaAudio_old(); + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend.media = new TLRPC.TL_decryptedMessageMediaAudio(); + } else { + reqSend.media = new TLRPC.TL_decryptedMessageMediaAudio_old(); + } reqSend.media.duration = audio.duration; reqSend.media.size = audio.size; reqSend.media.mime_type = "audio/ogg"; @@ -1102,14 +1116,28 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter }), true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassCanCompress, ConnectionsManager.DEFAULT_DATACENTER_ID); } - private void performSendEncryptedRequest(final TLRPC.DecryptedMessage req, final MessageObject newMsgObj, final TLRPC.EncryptedChat chat, final TLRPC.InputEncryptedFile encryptedFile, final String originalPath) { + private void performSendEncryptedRequest(final TLRPC.DecryptedMessage req, final MessageObject newMsgObj, final TLRPC.EncryptedChat chat, final TLRPC.InputEncryptedFile encryptedFile, final String originalPath, final Runnable callback) { if (req == null || chat.auth_key == null || chat instanceof TLRPC.TL_encryptedChatRequested || chat instanceof TLRPC.TL_encryptedChatWaiting) { return; } - int len = req.getObjectSize(); + TLObject toEncryptObject = null; + if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 17) { + TLRPC.TL_decryptedMessageLayer layer = new TLRPC.TL_decryptedMessageLayer(); + layer.layer = CURRENT_SECRET_CHAT_LAYER; + layer.in_seq_no = 0; //TODO + layer.out_seq_no = 0; + layer.message = req; + layer.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))]; + Utilities.random.nextBytes(layer.random_bytes); + toEncryptObject = layer; + } else { + toEncryptObject = req; + } + + int len = toEncryptObject.getObjectSize(); ByteBufferDesc toEncrypt = BuffersStorage.getInstance().getFreeBuffer(4 + len); toEncrypt.writeInt32(len); - req.serializeToStream(toEncrypt); + toEncryptObject.serializeToStream(toEncrypt); byte[] messageKeyFull = Utilities.computeSHA1(toEncrypt.buffer); byte[] messageKey = new byte[16]; @@ -1162,6 +1190,9 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter ConnectionsManager.getInstance().performRpc(reqToSend, new RPCRequest.RPCRequestDelegate() { @Override public void run(TLObject response, TLRPC.TL_error error) { + if (error == null && callback != null) { + callback.run(); + } if (newMsgObj != null) { if (error == null) { final String attachPath = newMsgObj.messageOwner.attachPath; @@ -1436,38 +1467,89 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { return; } - TLRPC.TL_decryptedMessageService_old reqSend = new TLRPC.TL_decryptedMessageService_old(); + TLRPC.TL_decryptedMessageService reqSend = null; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessageService(); + } else { + reqSend = new TLRPC.TL_decryptedMessageService_old(); + reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))]; + Utilities.random.nextBytes(reqSend.random_bytes); + } reqSend.random_id = getNextRandomId(); - reqSend.random_bytes = new byte[Math.max(1, (int)Math.ceil(Utilities.random.nextDouble() * 16))]; - Utilities.random.nextBytes(reqSend.random_bytes); reqSend.action = new TLRPC.TL_decryptedMessageActionReadMessages(); reqSend.action.random_ids = random_ids; - performSendEncryptedRequest(reqSend, null, encryptedChat, null, null); + performSendEncryptedRequest(reqSend, null, encryptedChat, null, null, null); } public void sendMessagesDeleteMessage(ArrayList random_ids, TLRPC.EncryptedChat encryptedChat) { if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { return; } - TLRPC.TL_decryptedMessageService_old reqSend = new TLRPC.TL_decryptedMessageService_old(); + TLRPC.TL_decryptedMessageService reqSend = null; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessageService(); + } else { + reqSend = new TLRPC.TL_decryptedMessageService_old(); + reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))]; + Utilities.random.nextBytes(reqSend.random_bytes); + } reqSend.random_id = getNextRandomId(); - reqSend.random_bytes = new byte[Math.max(1, (int)Math.ceil(Utilities.random.nextDouble() * 16))]; - Utilities.random.nextBytes(reqSend.random_bytes); reqSend.action = new TLRPC.TL_decryptedMessageActionDeleteMessages(); reqSend.action.random_ids = random_ids; - performSendEncryptedRequest(reqSend, null, encryptedChat, null, null); + performSendEncryptedRequest(reqSend, null, encryptedChat, null, null, null); } public void sendClearHistoryMessage(TLRPC.EncryptedChat encryptedChat) { if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { return; } - TLRPC.TL_decryptedMessageService_old reqSend = new TLRPC.TL_decryptedMessageService_old(); + TLRPC.TL_decryptedMessageService reqSend = null; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessageService(); + } else { + reqSend = new TLRPC.TL_decryptedMessageService_old(); + reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))]; + Utilities.random.nextBytes(reqSend.random_bytes); + } reqSend.random_id = getNextRandomId(); - reqSend.random_bytes = new byte[Math.max(1, (int)Math.ceil(Utilities.random.nextDouble() * 16))]; - Utilities.random.nextBytes(reqSend.random_bytes); reqSend.action = new TLRPC.TL_decryptedMessageActionFlushHistory(); - performSendEncryptedRequest(reqSend, null, encryptedChat, null, null); + performSendEncryptedRequest(reqSend, null, encryptedChat, null, null, null); + } + + public void sendNotifyLayerMessage(final TLRPC.EncryptedChat encryptedChat) { + if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { + return; + } + if (sendingNotifyLayer.contains(encryptedChat.id)) { + return; + } + sendingNotifyLayer.add(encryptedChat.id); + TLRPC.TL_decryptedMessageService reqSend = null; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessageService(); + } else { + reqSend = new TLRPC.TL_decryptedMessageService_old(); + reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))]; + Utilities.random.nextBytes(reqSend.random_bytes); + } + reqSend.random_id = getNextRandomId(); + reqSend.action = new TLRPC.TL_decryptedMessageActionNotifyLayer(); + reqSend.action.layer = CURRENT_SECRET_CHAT_LAYER; + Runnable callback = new Runnable() { + @Override + public void run() { + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + TLRPC.EncryptedChat chat = MessagesController.getInstance().getEncryptedChat(encryptedChat.id); + sendingNotifyLayer.remove(chat.id); + chat.layer = AndroidUtilities.setMyLayerVersion(chat.layer, CURRENT_SECRET_CHAT_LAYER); + MessagesStorage.getInstance().updateEncryptedChatLayer(chat); + } + }); + } + }; + performSendEncryptedRequest(reqSend, null, encryptedChat, null, null, callback); } public void sendTTLMessage(TLRPC.EncryptedChat encryptedChat) { @@ -1502,13 +1584,18 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter MessagesController.getInstance().updateInterfaceWithMessages(newMsg.dialog_id, objArr); NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); - TLRPC.TL_decryptedMessageService_old reqSend = new TLRPC.TL_decryptedMessageService_old(); + TLRPC.TL_decryptedMessageService reqSend = null; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessageService(); + } else { + reqSend = new TLRPC.TL_decryptedMessageService_old(); + reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))]; + Utilities.random.nextBytes(reqSend.random_bytes); + } reqSend.random_id = newMsg.random_id; - reqSend.random_bytes = new byte[Math.max(1, (int)Math.ceil(Utilities.random.nextDouble() * 16))]; - Utilities.random.nextBytes(reqSend.random_bytes); reqSend.action = new TLRPC.TL_decryptedMessageActionSetMessageTTL(); reqSend.action.ttl_seconds = encryptedChat.ttl; - performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null, null); + performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null, null, null); } public void sendScreenshotMessage(TLRPC.EncryptedChat encryptedChat, ArrayList random_ids) { @@ -1548,12 +1635,17 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter MessagesController.getInstance().updateInterfaceWithMessages(newMsg.dialog_id, objArr); NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); - TLRPC.TL_decryptedMessageService_old reqSend = new TLRPC.TL_decryptedMessageService_old(); + TLRPC.TL_decryptedMessageService reqSend = null; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessageService(); + } else { + reqSend = new TLRPC.TL_decryptedMessageService_old(); + reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))]; + Utilities.random.nextBytes(reqSend.random_bytes); + } reqSend.random_id = newMsg.random_id; - reqSend.random_bytes = new byte[Math.max(1, (int)Math.ceil(Utilities.random.nextDouble() * 16))]; - Utilities.random.nextBytes(reqSend.random_bytes); reqSend.action = action; - performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null, null); + performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null, null, null); } private void putToDelayedMessages(String location, DelayedMessage message) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/DispatchQueue.java b/TMessagesProj/src/main/java/org/telegram/messenger/DispatchQueue.java index 15a573a9..2c68fdf6 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/DispatchQueue.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/DispatchQueue.java @@ -63,7 +63,7 @@ public class DispatchQueue extends Thread { postRunnable(runnable, 0); } - public void postRunnable(Runnable runnable, int delay) { + public void postRunnable(Runnable runnable, long delay) { if (handler == null) { synchronized (handlerSyncObject) { if (handler == null) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java index eb33d919..1de7d7df 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java @@ -2557,8 +2557,6 @@ public class TLRPC { public static class DecryptedMessage extends TLObject { public long random_id; public byte[] random_bytes; - public int in_seq_no; - public int out_seq_no; public DecryptedMessageAction action; public int ttl; public String message; @@ -2566,36 +2564,27 @@ public class TLRPC { } public static class TL_decryptedMessageService extends DecryptedMessage { - public static int constructor = 0xda431693; + public static int constructor = 0x73164160; public void readParams(AbsSerializedData stream) { random_id = stream.readInt64(); - random_bytes = stream.readByteArray(); - in_seq_no = stream.readInt32(); - out_seq_no = stream.readInt32(); action = (DecryptedMessageAction)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); } public void serializeToStream(AbsSerializedData stream) { stream.writeInt32(constructor); stream.writeInt64(random_id); - stream.writeByteArray(random_bytes); - stream.writeInt32(in_seq_no); - stream.writeInt32(out_seq_no); action.serializeToStream(stream); } } public static class TL_decryptedMessage extends DecryptedMessage { - public static int constructor = 0x4e748938; + public static int constructor = 0x204d3878; public void readParams(AbsSerializedData stream) { random_id = stream.readInt64(); - random_bytes = stream.readByteArray(); - in_seq_no = stream.readInt32(); - out_seq_no = stream.readInt32(); ttl = stream.readInt32(); message = stream.readString(); media = (DecryptedMessageMedia)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); @@ -2604,9 +2593,6 @@ public class TLRPC { public void serializeToStream(AbsSerializedData stream) { stream.writeInt32(constructor); stream.writeInt64(random_id); - stream.writeByteArray(random_bytes); - stream.writeInt32(in_seq_no); - stream.writeInt32(out_seq_no); stream.writeInt32(ttl); stream.writeString(message); media.serializeToStream(stream); @@ -6281,19 +6267,28 @@ public class TLRPC { } public static class TL_decryptedMessageLayer extends TLObject { - public static int constructor = 0x99a438cf; + public static int constructor = 0x1be31789; + public byte[] random_bytes; public int layer; + public int in_seq_no; + public int out_seq_no; public DecryptedMessage message; public void readParams(AbsSerializedData stream) { + random_bytes = stream.readByteArray(); layer = stream.readInt32(); + in_seq_no = stream.readInt32(); + out_seq_no = stream.readInt32(); message = (DecryptedMessage)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); } public void serializeToStream(AbsSerializedData stream) { stream.writeInt32(constructor); + stream.writeByteArray(random_bytes); stream.writeInt32(layer); + stream.writeInt32(in_seq_no); + stream.writeInt32(out_seq_no); message.serializeToStream(stream); } } @@ -8781,6 +8776,7 @@ public class TLRPC { public long dialog_id; public int ttl; public int destroyTime; + public int layer; public VideoEditedInfo videoEditedInfo = null; } @@ -9663,24 +9659,6 @@ public class TLRPC { } } - public static class decryptedMessageLayer extends TLObject { - public static int constructor = 0x99a438cf; - - public int layer; - public TLObject message; - - public void readParams(AbsSerializedData stream) { - layer = stream.readInt32(); - message = TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); - } - - public void serializeToStream(AbsSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(layer); - message.serializeToStream(stream); - } - } - public static class TL_encryptedChat_old extends TL_encryptedChat { public static int constructor = 0x6601d14f; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java index aa2495a7..4dc2997f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java @@ -26,7 +26,6 @@ import org.telegram.android.AndroidUtilities; import org.telegram.messenger.FileLog; import org.telegram.android.LocaleController; import org.telegram.messenger.R; -import org.telegram.messenger.Utilities; import org.telegram.ui.Views.ActionBar.ActionBarLayer; import org.telegram.ui.Views.ActionBar.ActionBarMenu; import org.telegram.ui.Views.ActionBar.BaseFragment; @@ -55,7 +54,13 @@ public class LoginActivity extends BaseFragment implements SlideView.SlideViewDe v.onDestroyActivity(); } } - Utilities.HideProgressDialog(getParentActivity()); + if (progressDialog != null) { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } } @Override From 2f23635e4a78851356141c0d72014608dd22e723 Mon Sep 17 00:00:00 2001 From: DrKLO Date: Wed, 15 Oct 2014 00:36:15 +0400 Subject: [PATCH 06/18] UI update --- .../telegram/android/AndroidUtilities.java | 95 ++ .../org/telegram/android/MessageObject.java | 22 +- .../telegram/android/MessagesController.java | 10 +- .../org/telegram/android/MessagesStorage.java | 10 +- .../telegram/android/SendMessagesHelper.java | 2 +- .../org/telegram/ui/Cells/ChatActionCell.java | 143 +++ .../org/telegram/ui/Cells/ChatBaseCell.java | 21 +- .../java/org/telegram/ui/ChatActivity.java | 66 +- .../java/org/telegram/ui/LoginActivity.java | 2 + .../java/org/telegram/ui/PhotoViewer.java | 12 +- .../org/telegram/ui/SettingsActivity.java | 32 +- .../org/telegram/ui/UserProfileActivity.java | 64 +- .../telegram/ui/Views/HorizontalListView.java | 10 +- .../org/telegram/ui/Views/NumberPicker.java | 1058 +++++++++++++++++ .../org/telegram/ui/Views/TimerButton.java | 41 +- .../res/drawable-hdpi/list_focused_holo.9.png | Bin 0 -> 191 bytes .../list_longpressed_holo_light.9.png | Bin 0 -> 158 bytes .../list_pressed_holo_light.9.png | Bin 0 -> 159 bytes .../list_selector_disabled_holo_light.9.png | Bin 0 -> 189 bytes .../numberpicker_selection_divider.9.png | Bin 0 -> 141 bytes .../res/drawable-mdpi/list_focused_holo.9.png | Bin 0 -> 171 bytes .../list_longpressed_holo_light.9.png | Bin 0 -> 155 bytes .../list_pressed_holo_light.9.png | Bin 0 -> 158 bytes .../list_selector_disabled_holo_light.9.png | Bin 0 -> 171 bytes .../numberpicker_selection_divider.9.png | Bin 0 -> 135 bytes .../drawable-xhdpi/list_focused_holo.9.png | Bin 0 -> 203 bytes .../list_longpressed_holo_light.9.png | Bin 0 -> 162 bytes .../list_pressed_holo_light.9.png | Bin 0 -> 163 bytes .../list_selector_disabled_holo_light.9.png | Bin 0 -> 188 bytes .../numberpicker_selection_divider.9.png | Bin 0 -> 142 bytes .../drawable-xxhdpi/list_focused_holo.9.png | Bin 0 -> 1079 bytes .../list_longpressed_holo_light.9.png | Bin 0 -> 1051 bytes .../list_pressed_holo_light.9.png | Bin 0 -> 1051 bytes .../numberpicker_selection_divider.9.png | Bin 0 -> 217 bytes .../drawable/item_background_holo_light.xml | 10 + ...ector_background_transition_holo_light.xml | 6 + .../src/main/res/values-ar/strings.xml | 44 +- .../src/main/res/values-de/strings.xml | 44 +- .../src/main/res/values-es/strings.xml | 48 +- .../src/main/res/values-it/strings.xml | 44 +- .../src/main/res/values-ko/strings.xml | 44 +- .../src/main/res/values-nl/strings.xml | 44 +- .../src/main/res/values-pt-rBR/strings.xml | 46 +- .../src/main/res/values-pt-rPT/strings.xml | 46 +- TMessagesProj/src/main/res/values/strings.xml | 44 +- 45 files changed, 1692 insertions(+), 316 deletions(-) create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Views/NumberPicker.java create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/list_focused_holo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/list_longpressed_holo_light.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/list_pressed_holo_light.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/list_selector_disabled_holo_light.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/numberpicker_selection_divider.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/list_focused_holo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/list_longpressed_holo_light.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/list_pressed_holo_light.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/list_selector_disabled_holo_light.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/numberpicker_selection_divider.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/list_focused_holo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/list_longpressed_holo_light.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/list_pressed_holo_light.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/list_selector_disabled_holo_light.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/numberpicker_selection_divider.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/list_focused_holo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/list_longpressed_holo_light.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/list_pressed_holo_light.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/numberpicker_selection_divider.9.png create mode 100644 TMessagesProj/src/main/res/drawable/item_background_holo_light.xml create mode 100644 TMessagesProj/src/main/res/drawable/list_selector_background_transition_holo_light.xml diff --git a/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java index 3c2dda04..21c5bc62 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java @@ -9,7 +9,9 @@ package org.telegram.android; import android.app.Activity; +import android.app.AlertDialog; import android.content.Context; +import android.content.DialogInterface; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Point; @@ -24,8 +26,10 @@ import android.view.inputmethod.InputMethodManager; import org.telegram.messenger.FileLog; import org.telegram.messenger.R; +import org.telegram.messenger.TLRPC; import org.telegram.messenger.UserConfig; import org.telegram.ui.ApplicationLoader; +import org.telegram.ui.Views.NumberPicker; import java.io.File; import java.util.Hashtable; @@ -240,6 +244,10 @@ public class AndroidUtilities { return (int)Math.ceil(density * value); } + public static float dpf2(float value) { + return density * value; + } + public static void checkDisplaySize() { try { WindowManager manager = (WindowManager)ApplicationLoader.applicationContext.getSystemService(Context.WINDOW_SERVICE); @@ -388,4 +396,91 @@ public class AndroidUtilities { } return photoSize; } + + public static String formatTTLString(int ttl) { + if (ttl < 60) { + return LocaleController.formatPluralString("Seconds", ttl); + } else if (ttl < 60 * 60) { + return LocaleController.formatPluralString("Minutes", ttl / 60); + } else if (ttl < 60 * 60 * 24) { + return LocaleController.formatPluralString("Hours", ttl / 60 / 60); + } else if (ttl < 60 * 60 * 24 * 7) { + return LocaleController.formatPluralString("Days", ttl / 60 / 60 / 24); + } else { + int days = ttl / 60 / 60 / 24; + if (ttl % 7 == 0) { + return LocaleController.formatPluralString("Weeks", days / 7); + } else { + return String.format("%s %s", LocaleController.formatPluralString("Weeks", days / 7), LocaleController.formatPluralString("Days", days % 7)); + } + } + } + + public static AlertDialog.Builder buildTTLAlert(Context context, final TLRPC.EncryptedChat encryptedChat) { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(LocaleController.getString("MessageLifetime", R.string.MessageLifetime)); + final NumberPicker numberPicker = new NumberPicker(context); + numberPicker.setMinValue(0); + numberPicker.setMaxValue(20); + if (encryptedChat.ttl >= 0 && encryptedChat.ttl < 16) { + numberPicker.setValue(encryptedChat.ttl); + } else if (encryptedChat.ttl == 30) { + numberPicker.setValue(16); + } else if (encryptedChat.ttl == 60) { + numberPicker.setValue(17); + } else if (encryptedChat.ttl == 60 * 60) { + numberPicker.setValue(18); + } else if (encryptedChat.ttl == 60 * 60 * 24) { + numberPicker.setValue(19); + } else if (encryptedChat.ttl == 60 * 60 * 24 * 7) { + numberPicker.setValue(20); + } + numberPicker.setFormatter(new NumberPicker.Formatter() { + @Override + public String format(int value) { + if (value == 0) { + return LocaleController.getString("ShortMessageLifetimeForever", R.string.ShortMessageLifetimeForever); + } else if (value >= 1 && value < 16) { + return AndroidUtilities.formatTTLString(value); + } else if (value == 16) { + return AndroidUtilities.formatTTLString(30); + } else if (value == 17) { + return AndroidUtilities.formatTTLString(60); + } else if (value == 18) { + return AndroidUtilities.formatTTLString(60 * 60); + } else if (value == 19) { + return AndroidUtilities.formatTTLString(60 * 60 * 24); + } else if (value == 20) { + return AndroidUtilities.formatTTLString(60 * 60 * 24 * 7); + } + return ""; + } + }); + builder.setView(numberPicker); + builder.setNegativeButton(LocaleController.getString("Done", R.string.Done), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + int oldValue = encryptedChat.ttl; + which = numberPicker.getValue(); + if (which >= 0 && which < 16) { + encryptedChat.ttl = which; + } else if (which == 16) { + encryptedChat.ttl = 30; + } else if (which == 17) { + encryptedChat.ttl = 60; + } else if (which == 18) { + encryptedChat.ttl = 60 * 60; + } else if (which == 19) { + encryptedChat.ttl = 60 * 60 * 24; + } else if (which == 20) { + encryptedChat.ttl = 60 * 60 * 24 * 7; + } + if (oldValue != encryptedChat.ttl) { + SendMessagesHelper.getInstance().sendTTLMessage(encryptedChat); + MessagesStorage.getInstance().updateEncryptedChatTTL(encryptedChat); + } + } + }); + return builder; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java index 20c7c11b..f6f92394 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java @@ -178,29 +178,13 @@ public class MessageObject { } } else if (message.action instanceof TLRPC.TL_messageActionTTLChange) { if (message.action.ttl != 0) { - String timeString; - if (message.action.ttl == 2) { - timeString = LocaleController.getString("MessageLifetime2s", R.string.MessageLifetime2s); - } else if (message.action.ttl == 5) { - timeString = LocaleController.getString("MessageLifetime5s", R.string.MessageLifetime5s); - } else if (message.action.ttl == 60) { - timeString = LocaleController.getString("MessageLifetime1m", R.string.MessageLifetime1m); - } else if (message.action.ttl == 60 * 60) { - timeString = LocaleController.getString("MessageLifetime1h", R.string.MessageLifetime1h); - } else if (message.action.ttl == 60 * 60 * 24) { - timeString = LocaleController.getString("MessageLifetime1d", R.string.MessageLifetime1d); - } else if (message.action.ttl == 60 * 60 * 24 * 7) { - timeString = LocaleController.getString("MessageLifetime1w", R.string.MessageLifetime1w); - } else { - timeString = String.format("%d", message.action.ttl); - } if (isFromMe()) { - messageText = LocaleController.formatString("MessageLifetimeChangedOutgoing", R.string.MessageLifetimeChangedOutgoing, timeString); + messageText = LocaleController.formatString("MessageLifetimeChangedOutgoing", R.string.MessageLifetimeChangedOutgoing, AndroidUtilities.formatTTLString(message.action.ttl)); } else { if (fromUser != null) { - messageText = LocaleController.formatString("MessageLifetimeChanged", R.string.MessageLifetimeChanged, fromUser.first_name, timeString); + messageText = LocaleController.formatString("MessageLifetimeChanged", R.string.MessageLifetimeChanged, fromUser.first_name, AndroidUtilities.formatTTLString(message.action.ttl)); } else { - messageText = LocaleController.formatString("MessageLifetimeChanged", R.string.MessageLifetimeChanged, "", timeString); + messageText = LocaleController.formatString("MessageLifetimeChanged", R.string.MessageLifetimeChanged, "", AndroidUtilities.formatTTLString(message.action.ttl)); } } } else { diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java index f2ee4c2f..f11d4fc5 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java @@ -1700,7 +1700,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter random_ids.add(random_id); SendMessagesHelper.getInstance().sendMessagesReadMessage(random_ids, chat); if (chat.ttl > 0) { - MessagesStorage.getInstance().createTaskForSecretChat(chat.id, 0, ConnectionsManager.getInstance().getCurrentTime(), 0, random_ids); + int time = ConnectionsManager.getInstance().getCurrentTime(); + MessagesStorage.getInstance().createTaskForSecretChat(chat.id, time, time, 0, random_ids); } //TODO resend request } @@ -3707,12 +3708,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter TLRPC.TL_messageService newMessage = new TLRPC.TL_messageService(); if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { newMessage.action = new TLRPC.TL_messageActionTTLChange(); + if (serviceMessage.action.ttl_seconds < 0 || serviceMessage.action.ttl_seconds > 60 * 60 * 24 * 365) { + serviceMessage.action.ttl_seconds = 60 * 60 * 24 * 365; + } newMessage.action.ttl = chat.ttl = serviceMessage.action.ttl_seconds; } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages) { newMessage.action = new TLRPC.TL_messageEcryptedAction(); newMessage.action.encryptedAction = serviceMessage.action; - } else { - return null; } newMessage.local_id = newMessage.id = UserConfig.getNewMessageId(); UserConfig.saveConfig(false); @@ -3761,7 +3763,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter return null; } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionReadMessages) { if (!serviceMessage.action.random_ids.isEmpty()) { - MessagesStorage.getInstance().createTaskForSecretChat(chat.id, 0, message.date, 1, serviceMessage.action.random_ids); + MessagesStorage.getInstance().createTaskForSecretChat(chat.id, ConnectionsManager.getInstance().getCurrentTime(), message.date, 1, serviceMessage.action.random_ids); } } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionNotifyLayer) { AndroidUtilities.RunOnUIThread(new Runnable() { diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java index ff3b6c2d..abbec523 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java @@ -862,7 +862,7 @@ public class MessagesStorage { } while (cursor.next()) { int mid = cursor.intValue(0); - int date = readTime + cursor.intValue(1); + int date = Math.min(readTime, time) + cursor.intValue(1); minDate = Math.min(minDate, date); ArrayList arr = messages.get(date); if (arr == null) { @@ -2198,8 +2198,8 @@ public class MessagesStorage { state.bindByteBuffer(2, data2.buffer); state.bindByteBuffer(3, data3.buffer); state.bindInteger(4, chat.ttl); - state.bindInteger(5, chat.id); - state.bindInteger(6, chat.layer); + state.bindInteger(5, chat.layer); + state.bindInteger(6, chat.id); state.step(); buffersStorage.reuseFreeBuffer(data); buffersStorage.reuseFreeBuffer(data2); @@ -2473,8 +2473,10 @@ public class MessagesStorage { private int getMessageMediaType(TLRPC.Message message) { if (message instanceof TLRPC.TL_message_secret && message.media instanceof TLRPC.TL_messageMediaPhoto && message.ttl != 0 && message.ttl <= 60) { return 1; + } else if (message.media instanceof TLRPC.TL_messageMediaPhoto || message.media instanceof TLRPC.TL_messageMediaVideo) { + return 0; } - return 0; + return -1; } private void putMessagesInternal(final ArrayList messages, final boolean withTransaction, final boolean isBroadcast, final int downloadMask) { diff --git a/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java index f8fb052b..b98618c5 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java @@ -1542,7 +1542,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter @Override public void run() { TLRPC.EncryptedChat chat = MessagesController.getInstance().getEncryptedChat(encryptedChat.id); - sendingNotifyLayer.remove(chat.id); + sendingNotifyLayer.remove((Integer)chat.id); chat.layer = AndroidUtilities.setMyLayerVersion(chat.layer, CURRENT_SECRET_CHAT_LAYER); MessagesStorage.getInstance().updateEncryptedChatLayer(chat); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java new file mode 100644 index 00000000..b9ec3da6 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java @@ -0,0 +1,143 @@ +/* + * This is the source code of Telegram for Android v. 1.7.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2014. + */ + +package org.telegram.ui.Cells; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; + +import org.telegram.android.AndroidUtilities; +import org.telegram.android.MessageObject; +import org.telegram.android.MessagesController; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.R; + +public class ChatActionCell extends BaseCell { + + private static Drawable backgroundBlack; + private static Drawable backgroundBlue; + private static TextPaint textPaint; + + private StaticLayout textLayout; + private int textWidth = 0; + private int textHeight = 0; + private int textX = 0; + private int textXLeft = 0; + private int textY = 0; + private boolean useBlackBackground = false; + private boolean wasLayout = false; + + private MessageObject currentMessageObject; + + public ChatActionCell(Context context) { + super(context); + if (backgroundBlack == null) { + backgroundBlack = getResources().getDrawable(R.drawable.system_black); + backgroundBlue = getResources().getDrawable(R.drawable.system_blue); + + textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + textPaint.setColor(0xffffffff); + } + textPaint.setTextSize(AndroidUtilities.dp(MessagesController.getInstance().fontSize)); + } + + public void setMessageObject(MessageObject messageObject) { + if (currentMessageObject == messageObject) { + return; + } + currentMessageObject = messageObject; + int size; + if (AndroidUtilities.isTablet()) { + size = AndroidUtilities.getMinTabletSide(); + } else { + size = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y); + } + textLayout = new StaticLayout(currentMessageObject.messageText, textPaint, size - AndroidUtilities.dp(30), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); + textHeight = 0; + textWidth = 0; + try { + int linesCount = textLayout.getLineCount(); + boolean hasNonRTL = false; + for (int a = 0; a < linesCount; a++) { + float lineWidth = 0; + float lineLeft = 0; + try { + lineWidth = textLayout.getLineWidth(a); + lineLeft = textLayout.getLineLeft(a); + textHeight = (int)Math.max(textHeight, Math.ceil(textLayout.getLineBottom(a))); + } catch (Exception e) { + FileLog.e("tmessages", e); + return; + } + + if (lineLeft == 0) { + hasNonRTL = true; + } + textWidth = (int)Math.max(textWidth, Math.ceil(lineWidth)); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + textY = AndroidUtilities.dp(7); + wasLayout = false; + requestLayout(); + } + + public void setUseBlackBackground(boolean value) { + useBlackBackground = value; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), textHeight + AndroidUtilities.dp(14)); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + if (currentMessageObject == null) { + super.onLayout(changed, left, top, right, bottom); + return; + } + if (!wasLayout || changed) { + textX = (right - left - textWidth) / 2; + textXLeft = (right - left - textLayout.getWidth()) / 2; + + wasLayout = true; + } + } + + @Override + protected void onDraw(Canvas canvas) { + if (currentMessageObject == null) { + return; + } + if (!wasLayout) { + requestLayout(); + return; + } + + Drawable backgroundDrawable = null; + if (useBlackBackground) { + backgroundDrawable = backgroundBlack; + } else { + backgroundDrawable = backgroundBlue; + } + backgroundDrawable.setBounds(textX - AndroidUtilities.dp(5), AndroidUtilities.dp(5), textX + textWidth + AndroidUtilities.dp(5), getMeasuredHeight() - AndroidUtilities.dp(5)); + backgroundDrawable.draw(canvas); + + canvas.save(); + canvas.translate(textXLeft, textY); + textLayout.draw(canvas); + canvas.restore(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java index 3ce74277..5d99a660 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java @@ -149,18 +149,6 @@ public class ChatBaseCell extends BaseCell { public ChatBaseCell(Context context) { super(context); - init(); - avatarImage = new ImageReceiver(this); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - avatarImage.clearImage(); - currentPhoto = null; - } - - private void init() { if (backgroundDrawableIn == null) { backgroundDrawableIn = getResources().getDrawable(R.drawable.msg_in); backgroundDrawableInSelected = getResources().getDrawable(R.drawable.msg_in_selected); @@ -199,6 +187,14 @@ public class ChatBaseCell extends BaseCell { forwardNamePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); forwardNamePaint.setTextSize(AndroidUtilities.dp(14)); } + avatarImage = new ImageReceiver(this); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + avatarImage.clearImage(); + currentPhoto = null; } @Override @@ -466,7 +462,6 @@ public class ChatBaseCell extends BaseCell { } - @Override protected void onDraw(Canvas canvas) { if (currentMessageObject == null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 5d913818..2fb13499 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -72,6 +72,7 @@ import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; import org.telegram.ui.Adapters.BaseFragmentAdapter; +import org.telegram.ui.Cells.ChatActionCell; import org.telegram.ui.Cells.ChatAudioCell; import org.telegram.ui.Cells.ChatBaseCell; import org.telegram.ui.Cells.ChatMediaCell; @@ -393,6 +394,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not typingDotsDrawable = new TypingDotsDrawable(); typingDotsDrawable.setIsChat(currentChat != null); + if (currentEncryptedChat != null && AndroidUtilities.getMyLayerVersion(currentEncryptedChat.layer) != SendMessagesHelper.CURRENT_SECRET_CHAT_LAYER) { + SendMessagesHelper.getInstance().sendNotifyLayerMessage(currentEncryptedChat); + } + return true; } @@ -801,6 +806,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (messageObject == null || !messageObject.isSecretMedia() || !cell.getPhotoImage().isInsideImage(x, y - top)) { break; } + File file = FileLoader.getPathToMessage(messageObject.messageOwner); + if (!file.exists()) { + break; + } startX = x; startY = y; openSecretPhotoRunnable = new Runnable() { @@ -1113,44 +1122,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (getParentActivity() == null) { return; } - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("MessageLifetime", R.string.MessageLifetime)); - builder.setItems(new CharSequence[]{ - LocaleController.getString("ShortMessageLifetimeForever", R.string.ShortMessageLifetimeForever), - LocaleController.getString("ShortMessageLifetime2s", R.string.ShortMessageLifetime2s), - LocaleController.getString("ShortMessageLifetime5s", R.string.ShortMessageLifetime5s), - LocaleController.getString("ShortMessageLifetime1m", R.string.ShortMessageLifetime1m), - LocaleController.getString("ShortMessageLifetime1h", R.string.ShortMessageLifetime1h), - LocaleController.getString("ShortMessageLifetime1d", R.string.ShortMessageLifetime1d), - LocaleController.getString("ShortMessageLifetime1w", R.string.ShortMessageLifetime1w) - - }, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - int oldValue = currentEncryptedChat.ttl; - if (which == 0) { - currentEncryptedChat.ttl = 0; - } else if (which == 1) { - currentEncryptedChat.ttl = 2; - } else if (which == 2) { - currentEncryptedChat.ttl = 5; - } else if (which == 3) { - currentEncryptedChat.ttl = 60; - } else if (which == 4) { - currentEncryptedChat.ttl = 60 * 60; - } else if (which == 5) { - currentEncryptedChat.ttl = 60 * 60 * 24; - } else if (which == 6) { - currentEncryptedChat.ttl = 60 * 60 * 24 * 7; - } - if (oldValue != currentEncryptedChat.ttl) { - SendMessagesHelper.getInstance().sendTTLMessage(currentEncryptedChat); - MessagesStorage.getInstance().updateEncryptedChat(currentEncryptedChat); - } - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showAlertDialog(builder); + showAlertDialog(AndroidUtilities.buildTTLAlert(getParentActivity(), currentEncryptedChat)); } }); timerButton.setTime(currentEncryptedChat.ttl); @@ -3460,41 +3432,48 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not offset = 0; } if (i == 0 && !endReached || !unread_end_reached && i == (messages.size() + 1 - offset)) { + View progressBar = null; if (view == null) { LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = li.inflate(R.layout.chat_loading_layout, viewGroup, false); - View progressBar = view.findViewById(R.id.progressLayout); + progressBar = view.findViewById(R.id.progressLayout); if (isCustomTheme) { progressBar.setBackgroundResource(R.drawable.system_loader2); } else { progressBar.setBackgroundResource(R.drawable.system_loader1); } - progressBar.setVisibility(loadsCount > 1 ? View.VISIBLE : View.INVISIBLE); + } else { + progressBar = view.findViewById(R.id.progressLayout); } + progressBar.setVisibility(loadsCount > 1 ? View.VISIBLE : View.INVISIBLE); + return view; } } final MessageObject message = messages.get(messages.size() - i - offset); int type = message.contentType; if (view == null) { - LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); if (type == 0) { view = new ChatMessageCell(mContext); } if (type == 1) { view = new ChatMediaCell(mContext); } else if (type == 7) { - view = li.inflate(R.layout.chat_action_message_layout, viewGroup, false); + view = new ChatActionCell(mContext); } else if (type == 8) { + LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = li.inflate(R.layout.chat_action_change_photo_layout, viewGroup, false); } else if (type == 3) { + LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = li.inflate(R.layout.chat_outgoing_contact_layout, viewGroup, false); } else if (type == 4) { + LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); if (currentChat != null) { view = li.inflate(R.layout.chat_group_incoming_contact_layout, viewGroup, false); } else { view = li.inflate(R.layout.chat_incoming_contact_layout, viewGroup, false); } } else if (type == 6) { + LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = li.inflate(R.layout.chat_unread_layout, viewGroup, false); } else if (type == 2) { view = new ChatAudioCell(mContext); @@ -3638,6 +3617,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (view instanceof ChatAudioCell && MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_AUDIO)) { ((ChatAudioCell)view).downloadAudioIfNeed(); } + } else if (view instanceof ChatActionCell) { + ((ChatActionCell)view).setMessageObject(message); + ((ChatActionCell)view).setUseBlackBackground(isCustomTheme); } else { ChatListRowHolderEx holder = (ChatListRowHolderEx)view.getTag(); if (holder == null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java index 4dc2997f..990fbc45 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java @@ -60,6 +60,7 @@ public class LoginActivity extends BaseFragment implements SlideView.SlideViewDe } catch (Exception e) { FileLog.e("tmessages", e); } + progressDialog = null; } } @@ -260,6 +261,7 @@ public class LoginActivity extends BaseFragment implements SlideView.SlideViewDe } catch (Exception e) { FileLog.e("tmessages", e); } + progressDialog = null; } public void setPage(int page, boolean animated, Bundle params, boolean back) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index 7fdf85c4..635ed904 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -611,12 +611,14 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return; } try { - int size[] = new int[1]; - TLRPC.FileLocation fileLocation = getFileLocation(currentIndex, size); - if (fileLocation == null) { - return; + File f = null; + + if (currentMessageObject != null) { + f = FileLoader.getPathToMessage(currentMessageObject.messageOwner); + } else if (currentFileLocation != null) { + f = FileLoader.getPathToAttach(currentFileLocation, avatarsUserId != 0); } - File f = FileLoader.getPathToAttach(fileLocation, avatarsUserId != 0); + if (f.exists()) { Intent intent = new Intent(Intent.ACTION_SEND); if (f.toString().endsWith("mp4")) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java index 0bff501e..8a0b4e9e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java @@ -59,6 +59,7 @@ import org.telegram.ui.Views.ActionBar.ActionBarLayer; import org.telegram.ui.Views.AvatarUpdater; import org.telegram.ui.Views.BackupImageView; import org.telegram.ui.Views.ActionBar.BaseFragment; +import org.telegram.ui.Views.NumberPicker; import java.io.File; import java.util.ArrayList; @@ -245,39 +246,24 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("TextSize", R.string.TextSize)); - builder.setItems(new CharSequence[] { - String.format("%d", 12), - String.format("%d", 13), - String.format("%d", 14), - String.format("%d", 15), - String.format("%d", 16), - String.format("%d", 17), - String.format("%d", 18), - String.format("%d", 19), - String.format("%d", 20), - String.format("%d", 21), - String.format("%d", 22), - String.format("%d", 23), - String.format("%d", 24), - String.format("%d", 25), - String.format("%d", 26), - String.format("%d", 27), - String.format("%d", 28), - String.format("%d", 29), - String.format("%d", 30)}, new DialogInterface.OnClickListener() { + final NumberPicker numberPicker = new NumberPicker(getParentActivity()); + numberPicker.setMinValue(12); + numberPicker.setMaxValue(30); + numberPicker.setValue(MessagesController.getInstance().fontSize); + builder.setView(numberPicker); + builder.setNegativeButton(LocaleController.getString("Done", R.string.Done), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); SharedPreferences.Editor editor = preferences.edit(); - editor.putInt("fons_size", 12 + which); - MessagesController.getInstance().fontSize = 12 + which; + editor.putInt("fons_size", numberPicker.getValue()); + MessagesController.getInstance().fontSize = numberPicker.getValue(); editor.commit(); if (listView != null) { listView.invalidateViews(); } } }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showAlertDialog(builder); } else if (i == enableAnimationsRow) { SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java index 31bf865d..84a121a0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java @@ -31,7 +31,6 @@ import org.telegram.messenger.TLRPC; import org.telegram.android.ContactsController; import org.telegram.messenger.FileLog; import org.telegram.android.MessagesController; -import org.telegram.android.MessagesStorage; import org.telegram.android.NotificationCenter; import org.telegram.messenger.R; import org.telegram.android.MessageObject; @@ -256,47 +255,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen if (getParentActivity() == null) { return; } - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("MessageLifetime", R.string.MessageLifetime)); - builder.setItems(new CharSequence[]{ - LocaleController.getString("ShortMessageLifetimeForever", R.string.ShortMessageLifetimeForever), - LocaleController.getString("ShortMessageLifetime2s", R.string.ShortMessageLifetime2s), - LocaleController.getString("ShortMessageLifetime5s", R.string.ShortMessageLifetime5s), - LocaleController.getString("ShortMessageLifetime1m", R.string.ShortMessageLifetime1m), - LocaleController.getString("ShortMessageLifetime1h", R.string.ShortMessageLifetime1h), - LocaleController.getString("ShortMessageLifetime1d", R.string.ShortMessageLifetime1d), - LocaleController.getString("ShortMessageLifetime1w", R.string.ShortMessageLifetime1w) - - }, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - int oldValue = currentEncryptedChat.ttl; - if (which == 0) { - currentEncryptedChat.ttl = 0; - } else if (which == 1) { - currentEncryptedChat.ttl = 2; - } else if (which == 2) { - currentEncryptedChat.ttl = 5; - } else if (which == 3) { - currentEncryptedChat.ttl = 60; - } else if (which == 4) { - currentEncryptedChat.ttl = 60 * 60; - } else if (which == 5) { - currentEncryptedChat.ttl = 60 * 60 * 24; - } else if (which == 6) { - currentEncryptedChat.ttl = 60 * 60 * 24 * 7; - } - if (oldValue != currentEncryptedChat.ttl) { - if (listView != null) { - listView.invalidateViews(); - } - SendMessagesHelper.getInstance().sendTTLMessage(currentEncryptedChat); - MessagesStorage.getInstance().updateEncryptedChat(currentEncryptedChat); - } - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showAlertDialog(builder); + showAlertDialog(AndroidUtilities.buildTTLAlert(getParentActivity(), currentEncryptedChat)); } else if (i == settingsNotificationsRow) { Bundle args = new Bundle(); args.putLong("dialog_id", dialog_id == 0 ? user_id : dialog_id); @@ -454,6 +413,13 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen } } + @Override + protected void onDialogDismiss() { + if (listView != null) { + listView.invalidateViews(); + } + } + @Override public void didSelectDialog(MessagesActivity messageFragment, long dialog_id, boolean param) { if (dialog_id != 0) { @@ -670,20 +636,8 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen divider.setVisibility(View.VISIBLE); if (encryptedChat.ttl == 0) { detailTextView.setText(LocaleController.getString("ShortMessageLifetimeForever", R.string.ShortMessageLifetimeForever)); - } else if (encryptedChat.ttl == 2) { - detailTextView.setText(LocaleController.getString("ShortMessageLifetime2s", R.string.ShortMessageLifetime2s)); - } else if (encryptedChat.ttl == 5) { - detailTextView.setText(LocaleController.getString("ShortMessageLifetime5s", R.string.ShortMessageLifetime5s)); - } else if (encryptedChat.ttl == 60) { - detailTextView.setText(LocaleController.getString("ShortMessageLifetime1m", R.string.ShortMessageLifetime1m)); - } else if (encryptedChat.ttl == 60 * 60) { - detailTextView.setText(LocaleController.getString("ShortMessageLifetime1h", R.string.ShortMessageLifetime1h)); - } else if (encryptedChat.ttl == 60 * 60 * 24) { - detailTextView.setText(LocaleController.getString("ShortMessageLifetime1d", R.string.ShortMessageLifetime1d)); - } else if (encryptedChat.ttl == 60 * 60 * 24 * 7) { - detailTextView.setText(LocaleController.getString("ShortMessageLifetime1w", R.string.ShortMessageLifetime1w)); } else { - detailTextView.setText(String.format("%d", encryptedChat.ttl)); + detailTextView.setText(AndroidUtilities.formatTTLString(encryptedChat.ttl)); } } } else if (type == 4) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/HorizontalListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/HorizontalListView.java index 277ea468..59fef1a8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/HorizontalListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/HorizontalListView.java @@ -23,8 +23,6 @@ import android.widget.AdapterView; import android.widget.ListAdapter; import android.widget.Scroller; -import org.telegram.messenger.R; - public class HorizontalListView extends AdapterView { public boolean mAlwaysOverrideTouch = true; @@ -209,7 +207,7 @@ public class HorizontalListView extends AdapterView { v = list.poll(); } View child = mAdapter.getView(mRightViewIndex, v, this); - child.setTag(R.string.CacheTag, type); + child.setTag(1, type); addAndMeasureChild(child, -1); rightEdge += child.getMeasuredWidth(); @@ -236,7 +234,7 @@ public class HorizontalListView extends AdapterView { v = list.poll(); } View child = mAdapter.getView(mLeftViewIndex, v, this); - child.setTag(R.string.CacheTag, type); + child.setTag(1, type); addAndMeasureChild(child, 0); leftEdge -= child.getMeasuredWidth(); @@ -250,7 +248,7 @@ public class HorizontalListView extends AdapterView { while (child != null && child.getRight() + dx <= 0) { mDisplayOffset += child.getMeasuredWidth(); - int type = (Integer) child.getTag(R.string.CacheTag); + int type = (Integer) child.getTag(1); LinkedList list = mRemovedViewQueue.get(type); if (list == null) { list = new LinkedList(); @@ -265,7 +263,7 @@ public class HorizontalListView extends AdapterView { child = getChildAt(getChildCount() - 1); while (child != null && child.getLeft() + dx >= getWidth()) { - int type = (Integer) child.getTag(R.string.CacheTag); + int type = (Integer) child.getTag(1); LinkedList list = mRemovedViewQueue.get(type); if (list == null) { list = new LinkedList(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/NumberPicker.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/NumberPicker.java new file mode 100644 index 00000000..3c94f8f9 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/NumberPicker.java @@ -0,0 +1,1058 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.ui.Views; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Paint.Align; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.SparseArray; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.animation.DecelerateInterpolator; +import android.widget.LinearLayout; +import android.widget.Scroller; +import android.widget.TextView; + +import org.telegram.messenger.R; + +import java.util.Locale; + +public class NumberPicker extends LinearLayout { + + private static final int SELECTOR_WHEEL_ITEM_COUNT = 3; + private static final long DEFAULT_LONG_PRESS_UPDATE_INTERVAL = 300; + private static final int SELECTOR_MIDDLE_ITEM_INDEX = SELECTOR_WHEEL_ITEM_COUNT / 2; + private static final int SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT = 8; + private static final int SELECTOR_ADJUSTMENT_DURATION_MILLIS = 800; + private static final int SNAP_SCROLL_DURATION = 300; + private static final float TOP_AND_BOTTOM_FADING_EDGE_STRENGTH = 0.9f; + private static final int UNSCALED_DEFAULT_SELECTION_DIVIDER_HEIGHT = 2; + private static final int UNSCALED_DEFAULT_SELECTION_DIVIDERS_DISTANCE = 48; + private static final int DEFAULT_LAYOUT_RESOURCE_ID = 0; + private static final int SIZE_UNSPECIFIED = -1; + + private final TextView mInputText; + private final int mSelectionDividersDistance; + private final int mMinHeight; + private final int mMaxHeight; + private final int mMinWidth; + private int mMaxWidth; + private final boolean mComputeMaxWidth; + private final int mTextSize; + private int mSelectorTextGapHeight; + private String[] mDisplayedValues; + private int mMinValue; + private int mMaxValue; + private int mValue; + private OnValueChangeListener mOnValueChangeListener; + private OnScrollListener mOnScrollListener; + private Formatter mFormatter; + private long mLongPressUpdateInterval = DEFAULT_LONG_PRESS_UPDATE_INTERVAL; + private final SparseArray mSelectorIndexToStringCache = new SparseArray(); + private final int[] mSelectorIndices = new int[SELECTOR_WHEEL_ITEM_COUNT]; + private final Paint mSelectorWheelPaint; + private final Drawable mVirtualButtonPressedDrawable; + private int mSelectorElementHeight; + private int mInitialScrollOffset = Integer.MIN_VALUE; + private int mCurrentScrollOffset; + private final Scroller mFlingScroller; + private final Scroller mAdjustScroller; + private int mPreviousScrollerY; + private ChangeCurrentByOneFromLongPressCommand mChangeCurrentByOneFromLongPressCommand; + private float mLastDownEventY; + private long mLastDownEventTime; + private float mLastDownOrMoveEventY; + private VelocityTracker mVelocityTracker; + private int mTouchSlop; + private int mMinimumFlingVelocity; + private int mMaximumFlingVelocity; + private boolean mWrapSelectorWheel; + private final int mSolidColor; + private final Drawable mSelectionDivider; + private final int mSelectionDividerHeight; + private int mScrollState = OnScrollListener.SCROLL_STATE_IDLE; + private boolean mIngonreMoveEvents; + private int mTopSelectionDividerTop; + private int mBottomSelectionDividerBottom; + private int mLastHoveredChildVirtualViewId; + private boolean mIncrementVirtualButtonPressed; + private boolean mDecrementVirtualButtonPressed; + private final PressedStateHelper mPressedStateHelper; + private int mLastHandledDownDpadKeyCode = -1; + + public interface OnValueChangeListener { + void onValueChange(NumberPicker picker, int oldVal, int newVal); + } + + public interface OnScrollListener { + public static int SCROLL_STATE_IDLE = 0; + public static int SCROLL_STATE_TOUCH_SCROLL = 1; + public static int SCROLL_STATE_FLING = 2; + + public void onScrollStateChange(NumberPicker view, int scrollState); + } + + public interface Formatter { + public String format(int value); + } + + public NumberPicker(Context context) { + this(context, null); + } + + public NumberPicker(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public NumberPicker(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + mSolidColor = 0; + mSelectionDivider = getResources().getDrawable(R.drawable.numberpicker_selection_divider); + + mSelectionDividerHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, UNSCALED_DEFAULT_SELECTION_DIVIDER_HEIGHT, getResources().getDisplayMetrics()); + mSelectionDividersDistance = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, UNSCALED_DEFAULT_SELECTION_DIVIDERS_DISTANCE, getResources().getDisplayMetrics()); + + mMinHeight = SIZE_UNSPECIFIED; + + mMaxHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 180, getResources().getDisplayMetrics()); + if (mMinHeight != SIZE_UNSPECIFIED && mMaxHeight != SIZE_UNSPECIFIED && mMinHeight > mMaxHeight) { + throw new IllegalArgumentException("minHeight > maxHeight"); + } + + mMinWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 64, getResources().getDisplayMetrics()); + + mMaxWidth = SIZE_UNSPECIFIED; + if (mMinWidth != SIZE_UNSPECIFIED && mMaxWidth != SIZE_UNSPECIFIED && mMinWidth > mMaxWidth) { + throw new IllegalArgumentException("minWidth > maxWidth"); + } + + mComputeMaxWidth = (mMaxWidth == SIZE_UNSPECIFIED); + + mVirtualButtonPressedDrawable = getResources().getDrawable(R.drawable.item_background_holo_light); + + mPressedStateHelper = new PressedStateHelper(); + + setWillNotDraw(false); + + mInputText = new TextView(getContext()); + addView(mInputText); + mInputText.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + mInputText.setGravity(Gravity.CENTER); + mInputText.setSingleLine(true); + mInputText.setBackground(null); + mInputText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18); + + ViewConfiguration configuration = ViewConfiguration.get(context); + mTouchSlop = configuration.getScaledTouchSlop(); + mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity(); + mMaximumFlingVelocity = configuration.getScaledMaximumFlingVelocity() / SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT; + mTextSize = (int) mInputText.getTextSize(); + + Paint paint = new Paint(); + paint.setAntiAlias(true); + paint.setTextAlign(Align.CENTER); + paint.setTextSize(mTextSize); + paint.setTypeface(mInputText.getTypeface()); + ColorStateList colors = mInputText.getTextColors(); + int color = colors.getColorForState(ENABLED_STATE_SET, Color.WHITE); + paint.setColor(color); + mSelectorWheelPaint = paint; + + mFlingScroller = new Scroller(getContext(), null, true); + mAdjustScroller = new Scroller(getContext(), new DecelerateInterpolator(2.5f)); + + updateInputTextView(); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + final int msrdWdth = getMeasuredWidth(); + final int msrdHght = getMeasuredHeight(); + + final int inptTxtMsrdWdth = mInputText.getMeasuredWidth(); + final int inptTxtMsrdHght = mInputText.getMeasuredHeight(); + final int inptTxtLeft = (msrdWdth - inptTxtMsrdWdth) / 2; + final int inptTxtTop = (msrdHght - inptTxtMsrdHght) / 2; + final int inptTxtRight = inptTxtLeft + inptTxtMsrdWdth; + final int inptTxtBottom = inptTxtTop + inptTxtMsrdHght; + mInputText.layout(inptTxtLeft, inptTxtTop, inptTxtRight, inptTxtBottom); + + if (changed) { + initializeSelectorWheel(); + initializeFadingEdges(); + mTopSelectionDividerTop = (getHeight() - mSelectionDividersDistance) / 2 - mSelectionDividerHeight; + mBottomSelectionDividerBottom = mTopSelectionDividerTop + 2 * mSelectionDividerHeight + mSelectionDividersDistance; + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int newWidthMeasureSpec = makeMeasureSpec(widthMeasureSpec, mMaxWidth); + final int newHeightMeasureSpec = makeMeasureSpec(heightMeasureSpec, mMaxHeight); + super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec); + final int widthSize = resolveSizeAndStateRespectingMinSize(mMinWidth, getMeasuredWidth(), widthMeasureSpec); + final int heightSize = resolveSizeAndStateRespectingMinSize(mMinHeight, getMeasuredHeight(), heightMeasureSpec); + setMeasuredDimension(widthSize, heightSize); + } + + private boolean moveToFinalScrollerPosition(Scroller scroller) { + scroller.forceFinished(true); + int amountToScroll = scroller.getFinalY() - scroller.getCurrY(); + int futureScrollOffset = (mCurrentScrollOffset + amountToScroll) % mSelectorElementHeight; + int overshootAdjustment = mInitialScrollOffset - futureScrollOffset; + if (overshootAdjustment != 0) { + if (Math.abs(overshootAdjustment) > mSelectorElementHeight / 2) { + if (overshootAdjustment > 0) { + overshootAdjustment -= mSelectorElementHeight; + } else { + overshootAdjustment += mSelectorElementHeight; + } + } + amountToScroll += overshootAdjustment; + scrollBy(0, amountToScroll); + return true; + } + return false; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + if (!isEnabled()) { + return false; + } + final int action = event.getActionMasked(); + switch (action) { + case MotionEvent.ACTION_DOWN: { + removeAllCallbacks(); + mInputText.setVisibility(View.INVISIBLE); + mLastDownOrMoveEventY = mLastDownEventY = event.getY(); + mLastDownEventTime = event.getEventTime(); + mIngonreMoveEvents = false; + if (mLastDownEventY < mTopSelectionDividerTop) { + if (mScrollState == OnScrollListener.SCROLL_STATE_IDLE) { + mPressedStateHelper.buttonPressDelayed(PressedStateHelper.BUTTON_DECREMENT); + } + } else if (mLastDownEventY > mBottomSelectionDividerBottom) { + if (mScrollState == OnScrollListener.SCROLL_STATE_IDLE) { + mPressedStateHelper.buttonPressDelayed(PressedStateHelper.BUTTON_INCREMENT); + } + } + getParent().requestDisallowInterceptTouchEvent(true); + if (!mFlingScroller.isFinished()) { + mFlingScroller.forceFinished(true); + mAdjustScroller.forceFinished(true); + onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); + } else if (!mAdjustScroller.isFinished()) { + mFlingScroller.forceFinished(true); + mAdjustScroller.forceFinished(true); + } else if (mLastDownEventY < mTopSelectionDividerTop) { + postChangeCurrentByOneFromLongPress(false, ViewConfiguration.getLongPressTimeout()); + } else if (mLastDownEventY > mBottomSelectionDividerBottom) { + postChangeCurrentByOneFromLongPress(true, ViewConfiguration.getLongPressTimeout()); + } + return true; + } + } + return false; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (!isEnabled()) { + return false; + } + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } + mVelocityTracker.addMovement(event); + int action = event.getActionMasked(); + switch (action) { + case MotionEvent.ACTION_MOVE: { + if (mIngonreMoveEvents) { + break; + } + float currentMoveY = event.getY(); + if (mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) { + int deltaDownY = (int) Math.abs(currentMoveY - mLastDownEventY); + if (deltaDownY > mTouchSlop) { + removeAllCallbacks(); + onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); + } + } else { + int deltaMoveY = (int) ((currentMoveY - mLastDownOrMoveEventY)); + scrollBy(0, deltaMoveY); + invalidate(); + } + mLastDownOrMoveEventY = currentMoveY; + } + break; + case MotionEvent.ACTION_UP: { + removeChangeCurrentByOneFromLongPress(); + mPressedStateHelper.cancel(); + VelocityTracker velocityTracker = mVelocityTracker; + velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity); + int initialVelocity = (int) velocityTracker.getYVelocity(); + if (Math.abs(initialVelocity) > mMinimumFlingVelocity) { + fling(initialVelocity); + onScrollStateChange(OnScrollListener.SCROLL_STATE_FLING); + } else { + int eventY = (int) event.getY(); + int deltaMoveY = (int) Math.abs(eventY - mLastDownEventY); + long deltaTime = event.getEventTime() - mLastDownEventTime; + if (deltaMoveY <= mTouchSlop && deltaTime < ViewConfiguration.getTapTimeout()) { + int selectorIndexOffset = (eventY / mSelectorElementHeight) - SELECTOR_MIDDLE_ITEM_INDEX; + if (selectorIndexOffset > 0) { + changeValueByOne(true); + mPressedStateHelper.buttonTapped( + PressedStateHelper.BUTTON_INCREMENT); + } else if (selectorIndexOffset < 0) { + changeValueByOne(false); + mPressedStateHelper.buttonTapped( + PressedStateHelper.BUTTON_DECREMENT); + } + } else { + ensureScrollWheelAdjusted(); + } + onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); + } + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + break; + } + return true; + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + final int action = event.getActionMasked(); + switch (action) { + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + removeAllCallbacks(); + break; + } + return super.dispatchTouchEvent(event); + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + final int keyCode = event.getKeyCode(); + switch (keyCode) { + case KeyEvent.KEYCODE_DPAD_CENTER: + case KeyEvent.KEYCODE_ENTER: + removeAllCallbacks(); + break; + case KeyEvent.KEYCODE_DPAD_DOWN: + case KeyEvent.KEYCODE_DPAD_UP: + switch (event.getAction()) { + case KeyEvent.ACTION_DOWN: + if (mWrapSelectorWheel || (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) + ? getValue() < getMaxValue() : getValue() > getMinValue()) { + requestFocus(); + mLastHandledDownDpadKeyCode = keyCode; + removeAllCallbacks(); + if (mFlingScroller.isFinished()) { + changeValueByOne(keyCode == KeyEvent.KEYCODE_DPAD_DOWN); + } + return true; + } + break; + case KeyEvent.ACTION_UP: + if (mLastHandledDownDpadKeyCode == keyCode) { + mLastHandledDownDpadKeyCode = -1; + return true; + } + break; + } + } + return super.dispatchKeyEvent(event); + } + + @Override + public boolean dispatchTrackballEvent(MotionEvent event) { + final int action = event.getActionMasked(); + switch (action) { + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + removeAllCallbacks(); + break; + } + return super.dispatchTrackballEvent(event); + } + + @Override + public void computeScroll() { + Scroller scroller = mFlingScroller; + if (scroller.isFinished()) { + scroller = mAdjustScroller; + if (scroller.isFinished()) { + return; + } + } + scroller.computeScrollOffset(); + int currentScrollerY = scroller.getCurrY(); + if (mPreviousScrollerY == 0) { + mPreviousScrollerY = scroller.getStartY(); + } + scrollBy(0, currentScrollerY - mPreviousScrollerY); + mPreviousScrollerY = currentScrollerY; + if (scroller.isFinished()) { + onScrollerFinished(scroller); + } else { + invalidate(); + } + } + + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + mInputText.setEnabled(enabled); + } + + @Override + public void scrollBy(int x, int y) { + int[] selectorIndices = mSelectorIndices; + if (!mWrapSelectorWheel && y > 0 && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) { + mCurrentScrollOffset = mInitialScrollOffset; + return; + } + if (!mWrapSelectorWheel && y < 0 && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mMaxValue) { + mCurrentScrollOffset = mInitialScrollOffset; + return; + } + mCurrentScrollOffset += y; + while (mCurrentScrollOffset - mInitialScrollOffset > mSelectorTextGapHeight) { + mCurrentScrollOffset -= mSelectorElementHeight; + decrementSelectorIndices(selectorIndices); + setValueInternal(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX], true); + if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) { + mCurrentScrollOffset = mInitialScrollOffset; + } + } + while (mCurrentScrollOffset - mInitialScrollOffset < -mSelectorTextGapHeight) { + mCurrentScrollOffset += mSelectorElementHeight; + incrementSelectorIndices(selectorIndices); + setValueInternal(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX], true); + if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mMaxValue) { + mCurrentScrollOffset = mInitialScrollOffset; + } + } + } + + @Override + protected int computeVerticalScrollOffset() { + return mCurrentScrollOffset; + } + + @Override + protected int computeVerticalScrollRange() { + return (mMaxValue - mMinValue + 1) * mSelectorElementHeight; + } + + @Override + protected int computeVerticalScrollExtent() { + return getHeight(); + } + + @Override + public int getSolidColor() { + return mSolidColor; + } + + public void setOnValueChangedListener(OnValueChangeListener onValueChangedListener) { + mOnValueChangeListener = onValueChangedListener; + } + + public void setOnScrollListener(OnScrollListener onScrollListener) { + mOnScrollListener = onScrollListener; + } + + public void setFormatter(Formatter formatter) { + if (formatter == mFormatter) { + return; + } + mFormatter = formatter; + initializeSelectorWheelIndices(); + updateInputTextView(); + } + + public void setValue(int value) { + setValueInternal(value, false); + } + + private void tryComputeMaxWidth() { + if (!mComputeMaxWidth) { + return; + } + int maxTextWidth = 0; + if (mDisplayedValues == null) { + float maxDigitWidth = 0; + for (int i = 0; i <= 9; i++) { + final float digitWidth = mSelectorWheelPaint.measureText(formatNumberWithLocale(i)); + if (digitWidth > maxDigitWidth) { + maxDigitWidth = digitWidth; + } + } + int numberOfDigits = 0; + int current = mMaxValue; + while (current > 0) { + numberOfDigits++; + current = current / 10; + } + maxTextWidth = (int) (numberOfDigits * maxDigitWidth); + } else { + final int valueCount = mDisplayedValues.length; + for (String mDisplayedValue : mDisplayedValues) { + final float textWidth = mSelectorWheelPaint.measureText(mDisplayedValue); + if (textWidth > maxTextWidth) { + maxTextWidth = (int) textWidth; + } + } + } + maxTextWidth += mInputText.getPaddingLeft() + mInputText.getPaddingRight(); + if (mMaxWidth != maxTextWidth) { + if (maxTextWidth > mMinWidth) { + mMaxWidth = maxTextWidth; + } else { + mMaxWidth = mMinWidth; + } + invalidate(); + } + } + + public boolean getWrapSelectorWheel() { + return mWrapSelectorWheel; + } + + public void setWrapSelectorWheel(boolean wrapSelectorWheel) { + final boolean wrappingAllowed = (mMaxValue - mMinValue) >= mSelectorIndices.length; + if ((!wrapSelectorWheel || wrappingAllowed) && wrapSelectorWheel != mWrapSelectorWheel) { + mWrapSelectorWheel = wrapSelectorWheel; + } + } + + public void setOnLongPressUpdateInterval(long intervalMillis) { + mLongPressUpdateInterval = intervalMillis; + } + + public int getValue() { + return mValue; + } + + public int getMinValue() { + return mMinValue; + } + + public void setMinValue(int minValue) { + if (mMinValue == minValue) { + return; + } + if (minValue < 0) { + throw new IllegalArgumentException("minValue must be >= 0"); + } + mMinValue = minValue; + if (mMinValue > mValue) { + mValue = mMinValue; + } + boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length; + setWrapSelectorWheel(wrapSelectorWheel); + initializeSelectorWheelIndices(); + updateInputTextView(); + tryComputeMaxWidth(); + invalidate(); + } + + public int getMaxValue() { + return mMaxValue; + } + + public void setMaxValue(int maxValue) { + if (mMaxValue == maxValue) { + return; + } + if (maxValue < 0) { + throw new IllegalArgumentException("maxValue must be >= 0"); + } + mMaxValue = maxValue; + if (mMaxValue < mValue) { + mValue = mMaxValue; + } + boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length; + setWrapSelectorWheel(wrapSelectorWheel); + initializeSelectorWheelIndices(); + updateInputTextView(); + tryComputeMaxWidth(); + invalidate(); + } + + public String[] getDisplayedValues() { + return mDisplayedValues; + } + + public void setDisplayedValues(String[] displayedValues) { + if (mDisplayedValues == displayedValues) { + return; + } + mDisplayedValues = displayedValues; + updateInputTextView(); + initializeSelectorWheelIndices(); + tryComputeMaxWidth(); + } + + @Override + protected float getTopFadingEdgeStrength() { + return TOP_AND_BOTTOM_FADING_EDGE_STRENGTH; + } + + @Override + protected float getBottomFadingEdgeStrength() { + return TOP_AND_BOTTOM_FADING_EDGE_STRENGTH; + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + removeAllCallbacks(); + } + + @Override + protected void onDraw(Canvas canvas) { + float x = (getRight() - getLeft()) / 2; + float y = mCurrentScrollOffset; + + if (mVirtualButtonPressedDrawable != null && mScrollState == OnScrollListener.SCROLL_STATE_IDLE) { + if (mDecrementVirtualButtonPressed) { + mVirtualButtonPressedDrawable.setState(PRESSED_STATE_SET); + mVirtualButtonPressedDrawable.setBounds(0, 0, getRight(), mTopSelectionDividerTop); + mVirtualButtonPressedDrawable.draw(canvas); + } + if (mIncrementVirtualButtonPressed) { + mVirtualButtonPressedDrawable.setState(PRESSED_STATE_SET); + mVirtualButtonPressedDrawable.setBounds(0, mBottomSelectionDividerBottom, getRight(), getBottom()); + mVirtualButtonPressedDrawable.draw(canvas); + } + } + + // draw the selector wheel + int[] selectorIndices = mSelectorIndices; + for (int i = 0; i < selectorIndices.length; i++) { + int selectorIndex = selectorIndices[i]; + String scrollSelectorValue = mSelectorIndexToStringCache.get(selectorIndex); + // Do not draw the middle item if input is visible since the input + // is shown only if the wheel is static and it covers the middle + // item. Otherwise, if the user starts editing the text via the + // IME he may see a dimmed version of the old value intermixed + // with the new one. + if (i != SELECTOR_MIDDLE_ITEM_INDEX || mInputText.getVisibility() != VISIBLE) { + canvas.drawText(scrollSelectorValue, x, y, mSelectorWheelPaint); + } + y += mSelectorElementHeight; + } + + // draw the selection dividers + if (mSelectionDivider != null) { + // draw the top divider + int topOfTopDivider = mTopSelectionDividerTop; + int bottomOfTopDivider = topOfTopDivider + mSelectionDividerHeight; + mSelectionDivider.setBounds(0, topOfTopDivider, getRight(), bottomOfTopDivider); + mSelectionDivider.draw(canvas); + + // draw the bottom divider + int bottomOfBottomDivider = mBottomSelectionDividerBottom; + int topOfBottomDivider = bottomOfBottomDivider - mSelectionDividerHeight; + mSelectionDivider.setBounds(0, topOfBottomDivider, getRight(), bottomOfBottomDivider); + mSelectionDivider.draw(canvas); + } + } + + private int makeMeasureSpec(int measureSpec, int maxSize) { + if (maxSize == SIZE_UNSPECIFIED) { + return measureSpec; + } + final int size = MeasureSpec.getSize(measureSpec); + final int mode = MeasureSpec.getMode(measureSpec); + switch (mode) { + case MeasureSpec.EXACTLY: + return measureSpec; + case MeasureSpec.AT_MOST: + return MeasureSpec.makeMeasureSpec(Math.min(size, maxSize), MeasureSpec.EXACTLY); + case MeasureSpec.UNSPECIFIED: + return MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.EXACTLY); + default: + throw new IllegalArgumentException("Unknown measure mode: " + mode); + } + } + + private int resolveSizeAndStateRespectingMinSize( + int minSize, int measuredSize, int measureSpec) { + if (minSize != SIZE_UNSPECIFIED) { + final int desiredWidth = Math.max(minSize, measuredSize); + return resolveSizeAndState(desiredWidth, measureSpec, 0); + } else { + return measuredSize; + } + } + + private void initializeSelectorWheelIndices() { + mSelectorIndexToStringCache.clear(); + int[] selectorIndices = mSelectorIndices; + int current = getValue(); + for (int i = 0; i < mSelectorIndices.length; i++) { + int selectorIndex = current + (i - SELECTOR_MIDDLE_ITEM_INDEX); + if (mWrapSelectorWheel) { + selectorIndex = getWrappedSelectorIndex(selectorIndex); + } + selectorIndices[i] = selectorIndex; + ensureCachedScrollSelectorValue(selectorIndices[i]); + } + } + + private void setValueInternal(int current, boolean notifyChange) { + if (mValue == current) { + return; + } + if (mWrapSelectorWheel) { + current = getWrappedSelectorIndex(current); + } else { + current = Math.max(current, mMinValue); + current = Math.min(current, mMaxValue); + } + int previous = mValue; + mValue = current; + updateInputTextView(); + if (notifyChange) { + notifyChange(previous, current); + } + initializeSelectorWheelIndices(); + invalidate(); + } + + private void changeValueByOne(boolean increment) { + mInputText.setVisibility(View.INVISIBLE); + if (!moveToFinalScrollerPosition(mFlingScroller)) { + moveToFinalScrollerPosition(mAdjustScroller); + } + mPreviousScrollerY = 0; + if (increment) { + mFlingScroller.startScroll(0, 0, 0, -mSelectorElementHeight, SNAP_SCROLL_DURATION); + } else { + mFlingScroller.startScroll(0, 0, 0, mSelectorElementHeight, SNAP_SCROLL_DURATION); + } + invalidate(); + } + + private void initializeSelectorWheel() { + initializeSelectorWheelIndices(); + int[] selectorIndices = mSelectorIndices; + int totalTextHeight = selectorIndices.length * mTextSize; + float totalTextGapHeight = (getBottom() - getTop()) - totalTextHeight; + float textGapCount = selectorIndices.length; + mSelectorTextGapHeight = (int) (totalTextGapHeight / textGapCount + 0.5f); + mSelectorElementHeight = mTextSize + mSelectorTextGapHeight; + int editTextTextPosition = mInputText.getBaseline() + mInputText.getTop(); + mInitialScrollOffset = editTextTextPosition - (mSelectorElementHeight * SELECTOR_MIDDLE_ITEM_INDEX); + mCurrentScrollOffset = mInitialScrollOffset; + updateInputTextView(); + } + + private void initializeFadingEdges() { + setVerticalFadingEdgeEnabled(true); + setFadingEdgeLength((getBottom() - getTop() - mTextSize) / 2); + } + + private void onScrollerFinished(Scroller scroller) { + if (scroller == mFlingScroller) { + if (!ensureScrollWheelAdjusted()) { + updateInputTextView(); + } + onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); + } else { + if (mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) { + updateInputTextView(); + } + } + } + + private void onScrollStateChange(int scrollState) { + if (mScrollState == scrollState) { + return; + } + mScrollState = scrollState; + if (mOnScrollListener != null) { + mOnScrollListener.onScrollStateChange(this, scrollState); + } + } + + private void fling(int velocityY) { + mPreviousScrollerY = 0; + + if (velocityY > 0) { + mFlingScroller.fling(0, 0, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE); + } else { + mFlingScroller.fling(0, Integer.MAX_VALUE, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE); + } + + invalidate(); + } + + private int getWrappedSelectorIndex(int selectorIndex) { + if (selectorIndex > mMaxValue) { + return mMinValue + (selectorIndex - mMaxValue) % (mMaxValue - mMinValue) - 1; + } else if (selectorIndex < mMinValue) { + return mMaxValue - (mMinValue - selectorIndex) % (mMaxValue - mMinValue) + 1; + } + return selectorIndex; + } + + private void incrementSelectorIndices(int[] selectorIndices) { + System.arraycopy(selectorIndices, 1, selectorIndices, 0, selectorIndices.length - 1); + int nextScrollSelectorIndex = selectorIndices[selectorIndices.length - 2] + 1; + if (mWrapSelectorWheel && nextScrollSelectorIndex > mMaxValue) { + nextScrollSelectorIndex = mMinValue; + } + selectorIndices[selectorIndices.length - 1] = nextScrollSelectorIndex; + ensureCachedScrollSelectorValue(nextScrollSelectorIndex); + } + + private void decrementSelectorIndices(int[] selectorIndices) { + System.arraycopy(selectorIndices, 0, selectorIndices, 1, selectorIndices.length - 1); + int nextScrollSelectorIndex = selectorIndices[1] - 1; + if (mWrapSelectorWheel && nextScrollSelectorIndex < mMinValue) { + nextScrollSelectorIndex = mMaxValue; + } + selectorIndices[0] = nextScrollSelectorIndex; + ensureCachedScrollSelectorValue(nextScrollSelectorIndex); + } + + private void ensureCachedScrollSelectorValue(int selectorIndex) { + SparseArray cache = mSelectorIndexToStringCache; + String scrollSelectorValue = cache.get(selectorIndex); + if (scrollSelectorValue != null) { + return; + } + if (selectorIndex < mMinValue || selectorIndex > mMaxValue) { + scrollSelectorValue = ""; + } else { + if (mDisplayedValues != null) { + int displayedValueIndex = selectorIndex - mMinValue; + scrollSelectorValue = mDisplayedValues[displayedValueIndex]; + } else { + scrollSelectorValue = formatNumber(selectorIndex); + } + } + cache.put(selectorIndex, scrollSelectorValue); + } + + private String formatNumber(int value) { + return (mFormatter != null) ? mFormatter.format(value) : formatNumberWithLocale(value); + } + + private boolean updateInputTextView() { + String text = (mDisplayedValues == null) ? formatNumber(mValue) : mDisplayedValues[mValue - mMinValue]; + if (!TextUtils.isEmpty(text) && !text.equals(mInputText.getText().toString())) { + mInputText.setText(text); + return true; + } + return false; + } + + private void notifyChange(int previous, int current) { + if (mOnValueChangeListener != null) { + mOnValueChangeListener.onValueChange(this, previous, mValue); + } + } + + private void postChangeCurrentByOneFromLongPress(boolean increment, long delayMillis) { + if (mChangeCurrentByOneFromLongPressCommand == null) { + mChangeCurrentByOneFromLongPressCommand = new ChangeCurrentByOneFromLongPressCommand(); + } else { + removeCallbacks(mChangeCurrentByOneFromLongPressCommand); + } + mChangeCurrentByOneFromLongPressCommand.setStep(increment); + postDelayed(mChangeCurrentByOneFromLongPressCommand, delayMillis); + } + + private void removeChangeCurrentByOneFromLongPress() { + if (mChangeCurrentByOneFromLongPressCommand != null) { + removeCallbacks(mChangeCurrentByOneFromLongPressCommand); + } + } + + private void removeAllCallbacks() { + if (mChangeCurrentByOneFromLongPressCommand != null) { + removeCallbacks(mChangeCurrentByOneFromLongPressCommand); + } + mPressedStateHelper.cancel(); + } + + private int getSelectedPos(String value) { + if (mDisplayedValues == null) { + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + // Ignore as if it's not a number we don't care + } + } else { + for (int i = 0; i < mDisplayedValues.length; i++) { + // Don't force the user to type in jan when ja will do + value = value.toLowerCase(); + if (mDisplayedValues[i].toLowerCase().startsWith(value)) { + return mMinValue + i; + } + } + + /* + * The user might have typed in a number into the month field i.e. + * 10 instead of OCT so support that too. + */ + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + // Ignore as if it's not a number we don't care + } + } + return mMinValue; + } + + private boolean ensureScrollWheelAdjusted() { + // adjust to the closest value + int deltaY = mInitialScrollOffset - mCurrentScrollOffset; + if (deltaY != 0) { + mPreviousScrollerY = 0; + if (Math.abs(deltaY) > mSelectorElementHeight / 2) { + deltaY += (deltaY > 0) ? -mSelectorElementHeight : mSelectorElementHeight; + } + mAdjustScroller.startScroll(0, 0, 0, deltaY, SELECTOR_ADJUSTMENT_DURATION_MILLIS); + invalidate(); + return true; + } + return false; + } + + class PressedStateHelper implements Runnable { + public static final int BUTTON_INCREMENT = 1; + public static final int BUTTON_DECREMENT = 2; + + private final int MODE_PRESS = 1; + private final int MODE_TAPPED = 2; + + private int mManagedButton; + private int mMode; + + public void cancel() { + mMode = 0; + mManagedButton = 0; + NumberPicker.this.removeCallbacks(this); + if (mIncrementVirtualButtonPressed) { + mIncrementVirtualButtonPressed = false; + invalidate(0, mBottomSelectionDividerBottom, getRight(), getBottom()); + } + mDecrementVirtualButtonPressed = false; + if (mDecrementVirtualButtonPressed) { + invalidate(0, 0, getRight(), mTopSelectionDividerTop); + } + } + + public void buttonPressDelayed(int button) { + cancel(); + mMode = MODE_PRESS; + mManagedButton = button; + NumberPicker.this.postDelayed(this, ViewConfiguration.getTapTimeout()); + } + + public void buttonTapped(int button) { + cancel(); + mMode = MODE_TAPPED; + mManagedButton = button; + NumberPicker.this.post(this); + } + + @Override + public void run() { + switch (mMode) { + case MODE_PRESS: { + switch (mManagedButton) { + case BUTTON_INCREMENT: { + mIncrementVirtualButtonPressed = true; + invalidate(0, mBottomSelectionDividerBottom, getRight(), getBottom()); + } + break; + case BUTTON_DECREMENT: { + mDecrementVirtualButtonPressed = true; + invalidate(0, 0, getRight(), mTopSelectionDividerTop); + } + } + } + break; + case MODE_TAPPED: { + switch (mManagedButton) { + case BUTTON_INCREMENT: { + if (!mIncrementVirtualButtonPressed) { + NumberPicker.this.postDelayed(this, + ViewConfiguration.getPressedStateDuration()); + } + mIncrementVirtualButtonPressed ^= true; + invalidate(0, mBottomSelectionDividerBottom, getRight(), getBottom()); + } + break; + case BUTTON_DECREMENT: { + if (!mDecrementVirtualButtonPressed) { + NumberPicker.this.postDelayed(this, + ViewConfiguration.getPressedStateDuration()); + } + mDecrementVirtualButtonPressed ^= true; + invalidate(0, 0, getRight(), mTopSelectionDividerTop); + } + } + } + break; + } + } + } + + class ChangeCurrentByOneFromLongPressCommand implements Runnable { + private boolean mIncrement; + + private void setStep(boolean increment) { + mIncrement = increment; + } + + @Override + public void run() { + changeValueByOne(mIncrement); + postDelayed(this, mLongPressUpdateInterval); + } + } + + static private String formatNumberWithLocale(int value) { + return String.format(Locale.getDefault(), "%d", value); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/TimerButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/TimerButton.java index 25257a58..9c6c4304 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/TimerButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/TimerButton.java @@ -65,20 +65,33 @@ public class TimerButton extends View { time = value; String timeString = null; - if (time == 2) { - timeString = "2s"; - } else if (time == 5) { - timeString = "5s"; - } else if (time == 60) { - timeString = "1m"; - } else if (time == 60 * 60) { - timeString = "1h"; - } else if (time == 60 * 60 * 24) { - timeString = "1d"; - } else if (time == 60 * 60 * 24 * 7) { - timeString = "1w"; + if (time >= 1 && time < 60) { + timeString = "" + value; + if (timeString.length() < 2) { + timeString += "s"; + } + } else if (time >= 60 && time < 60 * 60) { + timeString = "" + value / 60; + if (timeString.length() < 2) { + timeString += "m"; + } + } else if (time >= 60 * 60 && time < 60 * 60 * 24) { + timeString = "" + value / 60 / 60; + if (timeString.length() < 2) { + timeString += "h"; + } + } else if (time >= 60 * 60 * 24 && time < 60 * 60 * 24 * 7) { + timeString = "" + value / 60 / 60 / 24; + if (timeString.length() < 2) { + timeString += "d"; + } } else { - timeString = "c"; + timeString = "" + value / 60 / 60 / 24 / 7; + if (timeString.length() < 2) { + timeString += "w"; + } else if (timeString.length() > 2) { + timeString = "c"; + } } timeWidth = timePaint.measureText(timeString); @@ -110,7 +123,7 @@ public class TimerButton extends View { drawable.draw(canvas); if (time != 0 && timeLayout != null) { - canvas.translate((width - timeWidth) / 2, (height - timeHeight) / 2 + AndroidUtilities.dp(1)); + canvas.translate((int)(width / 2 - Math.ceil(timeWidth / 2)), (height - timeHeight) / 2 + AndroidUtilities.dpf2(1.5f)); timeLayout.draw(canvas); } } diff --git a/TMessagesProj/src/main/res/drawable-hdpi/list_focused_holo.9.png b/TMessagesProj/src/main/res/drawable-hdpi/list_focused_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..555270842a739eb45d404ab473ad38a4c730240c GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1|(OmDOUqhEX7WqAsj$Z!;#Vf2?p zbb>IW`N`93fr5#iE{-7*Q>RY2$k|}PUG3I8+hq?M&UySt({#?YOY9F7 zV)|4jusAQAw~U49z^wIm)#n)N-o9e&+IDtd30r~4TeZ_)uKQd*6*KFj^h@OhGw-CF i@bOgmX?1Mk5ox7hDXx8`mUDoXF?hQAxvX2?p zbb>IW`N`93fr1X6E{-7*Q%#Yu{jSZY6_r0*XaPU~Kw7H>RPz#So x*q`|ew2FMyJPjWoux@6QYW~leSYKby#;`O{WM{qLW{?XQJYD@<);T3K0RTWvFIxZr literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/list_pressed_holo_light.9.png b/TMessagesProj/src/main/res/drawable-hdpi/list_pressed_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..2054530ed2870bfa7dbc60a2d142ba3776e63d33 GIT binary patch literal 159 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1|(OmDOUqhEX7WqAsj$Z!;#Vf2?p zbb>IW`N`93fr5^nE{-7*QCu0d(23bbo?Vjc_au2PNc{2VI6ud7G9!a*tc2mrrkFoK!x%hW{an^LB{Ts56WK1# literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/list_selector_disabled_holo_light.9.png b/TMessagesProj/src/main/res/drawable-hdpi/list_selector_disabled_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..ca8e9a2778f58deb3be0cba0d7af89400525896a GIT binary patch literal 189 zcmeAS@N?(olHy`uVBq!ia0vp^;y~=k!3HF){@Qy1DVAa<&kznEsNqQI0P;BtJR*x3 z7`Qt@n9=;?>9s(?cuyC{kcif|*Eb3_81S$-+V)J@yPBVWyvqG&GeYz~KYxJdw0eeyIoHJnOEfn# R{sUUY;OXk;vd$@?2>|r{LWckV literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/numberpicker_selection_divider.9.png b/TMessagesProj/src/main/res/drawable-hdpi/numberpicker_selection_divider.9.png new file mode 100644 index 0000000000000000000000000000000000000000..c9c72ba61947b714ec303af2d0a87eab4ba9fdeb GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^tRT$61|)m))t&+=mSQK*5Dp-y;YjHK@;M7UB8wRq zxI00Z(fs7;wLn3APZ!4!j+wbV8+jQN1X?T}yPbO{(f6@9Ve#F`7Xli%9)zc=6~48y hnPicXp?vo<6WbTDsrETbX9Kk|c)I$ztaD0e0s!FaC|Lji literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/list_focused_holo.9.png b/TMessagesProj/src/main/res/drawable-mdpi/list_focused_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..00f05d8c97e7963f23dc48a79ec0b09b88d52e20 GIT binary patch literal 171 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqEX7WqAsj$Z!;#Vf4nJ zaCd?*qxs3xYk`8ko-U3d5>tD79C;fY1elknGfSSZkgss!Fq+WV_wb)ql1{DGd2)`S!@o4yre42YU?3urKd Mr>mdKI;Vst081n_F8}}l literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/list_longpressed_holo_light.9.png b/TMessagesProj/src/main/res/drawable-mdpi/list_longpressed_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..3226ab760aaa0c15b1fcab6d993bce639f0676dd GIT binary patch literal 155 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqEX7WqAsj$Z!;#Vf4nJ zaCd?*qxs3xYk`8co-U3d5>uD#j+S3j3^P64nJ zaCd?*qxs3xYk`6eo-U3d5>u0BSQe`>3;p0f$^!z%>E}`sT8w%mH#B_t^2ONahROs+ w;Y|~FhzOW8PE-<>Sa9!8KkxZDmXjG7KBtQ4PiOt712l`l)78&qol`;+06UH>DgXcg literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/list_selector_disabled_holo_light.9.png b/TMessagesProj/src/main/res/drawable-mdpi/list_selector_disabled_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..42cb6463e4c28c6aeffa315c4fc869867dbb6b7c GIT binary patch literal 171 zcmeAS@N?(olHy`uVBq!ia0vp^{6MVD!3HFkzrK_Oq*#ibJVQ8upoSx*1IXtr@Q5sC zVBqcqVMg@oJyIHz9Y|%SiynA|kd)58s-{92FmHki*;@KxND!%;H%=F4ZU(n;yg$GVRgBd(s L{an^LB{Ts54)-;@ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/numberpicker_selection_divider.9.png b/TMessagesProj/src/main/res/drawable-mdpi/numberpicker_selection_divider.9.png new file mode 100644 index 0000000000000000000000000000000000000000..076fc16642176d49cc1b162d4838de91ce6e27f6 GIT binary patch literal 135 zcmeAS@N?(olHy`uVBq!ia0vp^EFjFm1|(O0oL2|p6gzo_Z~#FKM@k2f&spFRSa9~641CF;R9N4Um`Tq}MWC=06dTk%OL+*#) ar-D=*+w0EX1GeE8VNeS)2#7n8DN4&t;ucLK6V`fk$Nk literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/list_longpressed_holo_light.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/list_longpressed_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..5532e88c2c65f7fc9f37bf5a90c5868864b47c9d GIT binary patch literal 162 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xamSQK*5Dp-y;YjHK@;M7UB8wRq zxI00Z(fs7;wLn1^PZ!4!jfu%0zJE_Y!1Ql%qR4~y@6R9LNd1v?xtBZV&W=K1VNIzC z2M=T%`CxN4cgcP?w_UeA;(K{6xb)3i@iD2szMhRiY@WpK7>BTvK=T+pUHx3vIVCg! E0Ltw((f|Me literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/list_pressed_holo_light.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/list_pressed_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..f4af9265719d65e1c500c2a9de627aff162a18cc GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xamSQK*5Dp-y;YjHK@;M7UB8wRq zxI00Z(fs7;wLn2vPZ!4!jfu%KEQ{5c#XiXME^e4`Bzf#c$z!IMFJGq5@VMB( z!{(;k_B=CB`LC(brMqswvQiq=2qh%>1r1WJE1Ls*cJ{|veUO|(2k}?c6(wzK1e5>OQxsgorF)iU^(Q8S`6? g%TvbW5Bsj4%+EhcOubus5M&^Or>mdKI;Vst093XqtN;K2 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/list_focused_holo.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/list_focused_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..76cad1739505238d03aa4c0b25887e5813a14df8 GIT binary patch literal 1079 zcmbVL%WKp?9F7)?6e}ot@W~KG5#3}a`^bZ??dGv|!L4Px;^INfCbPS-O(rH&ce@9v zf@r~libpHn6a=pd9uySOL;nGL_M!)Go`gEtcB_ZdgMnlo`F-E_doD~)oEsiGIK*+> zaB1AEuytSZ?i^&_#f2loY&k%!8l55y+O{Li6ZUlOl{EdXM$MkL6JQq;AlM3QveFhW9PUMBuBLPSl?K+vId7gQ?7J?s^%NxW&yq+kQGO=Ta zA`+nJ`$=3q>zG#XUpF?jj;nJa7ArU=vysE<(Kyxzv)pYhlo&E^v)CtvIKJqLW+ShrmRcFqH1NOjMC@W44X?EhMtv_qG=$6EU24M zRjjlM(>WC?y4uHmrX;EoGSlyX$rhm`ZjlfeQ&~{9 z9WO}ENqN?yHF4zKz-}=jKIr9F^ES~}CEbt;mRdk-aTf|Y()FC2HLYwx$;kXV*8QKH ziOd->X^wxIrGLdbFxhUjK09m-4-VMGL~JzPobkT1v1*pgLbda?{(E(GbU=9j`SZPt zdtcn$^Ze+8TPIeYF1ydRD?d_8pFWOZcny4;-|;we|Ml6WJI2k^yRVZcgL~~$-OKLb z#eI)HJa~9~pm5;Gg)6^~E}#1Fek@#AeEH(!{`tzTvH5M>${}EkqaTfAluOox`AWZf F`ww_FQj-7x literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/list_longpressed_holo_light.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/list_longpressed_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..230d649bf730871f6f538cd7cf957d0aa894f899 GIT binary patch literal 1051 zcmbVL&ui0A9FL3*8Jl|0!vyh>T@-BcUYevySe$Lsx`LghD_A@&P2SqLB`+p#HX8`y zK^!Q0(1R#=@Svdh4|q^;7yknlFa8B02=k^dZ8Js24u&M}z3=;eKHuM4jm7iRlgB4H zj+?G6SWUJbO}~Q^?00nUv?JjO&+ugYO0nc&VSkG&< zX}f;GaELG1sg98NAwzTA+p#{3WFh>tPx9yoJpOFKsTi zoXu57clr6VU@kEjfsd&T5`Qg-jl|>!yawB+Vvz>}6}oEjL#NvH1}KvV14YQ^9EcE5 zRRPJ0s-iPMf=Ch}d(|A04MjDi0vJ6!vlh84M$@W}Y_XHc_b3ewQSA5oLO(B%s4F5} z*HaEj$}x>xyb(}4$p!Ij#$e&tiM)_{BmgO+-68ALQKDGN#KaCo zBtX&k)3^rOF>T^MZtSTYw>Cm7HgQbWBZt*vWi|t|-0g2DRb<{67bA}q#a^?Bv+m=7 z)-01}H-hWA21FXmVnK!l391@GS{cb!p(ItSdPR|BE#ue=TZBpx$`ynZ$wH`-*Gp2V zsK}OlwBd#MBNPoZ0o5-4Pbc}WGQ>bBzr zso->4pkcfgj=XEwtwzKLgA5zq9v;BLKaoQ%U(V}!3CXG|L4_Y--T%p&$ea<=_V}w^ zG7;;+bi3R9?65mNIAAjqvEg|2aI| ObX;qdMeB8G`Q~rOt3*x! literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/list_pressed_holo_light.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/list_pressed_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..1352a1702a7bd044d5e9eb2424f2501b3360abe8 GIT binary patch literal 1051 zcmbVLzi-n(6gH};P(^_Oh9V(Oj)XuWw$FAP+o~zC9k-E4iPA_!EUjZ-8`Iin>??6Q zp$>=&D!MQrP!|T6SP^1iXcztkHa0f?1K^y-g`w(zW&3`;?|bik_uh7Ees*%=@&v;$ zlZ`pMO~;G*cV?Xacebxg(qW3!yJP_`lYyHcrsm@w0*%mJL2cyv8xOytX@(i=2c0hI zHt*;j4mmfs;j%EMXoi`d$zs=AMFjNFN)Q?B&(B|25cmdruhJBnv4#4<+-8CnHs?Fu z=BlUp?944No#~VyM8pMIxE7^)X0StEozC-Zo&`e_vTCr0L3NugVBrLT3MZ940YacC z9F!}H0&fCQfFdu@S1ChTuPC}$1*32}LF2GdJcT zC-7mI=QXrWNgMqQ<5=sovk@b{jZ(axc=SG&O9hx}ce110kVd25O#*r;?wXCg^$RgomqQ5~q(9SG}^saQ2r zu2)UfavVpk6xc?T5;yWt;WwauN7(v_SlvpHOK{S`c&(^_Rv#0b_HhiX1qEDhx?T|F z8#nR`I?UHbN$?2yPJ%-)R9Fv=i9k`RHOZ6}OBiJ?sFLbvR1jINX_mx}u>Sw3#?xT< zygdFXmtu?7U_L!6e!4hn9~9A^NoaFCTl_Rj8>`WBO_I_P`t+vjW zIOBP1Y-j2{^Z1;)e{dTK55T3f2QOu3KUSxn@^4=}`7XfSQ}=tn-;IyII(=b@k+(|e S$9VBa-mZ=My#2vk+WG^{9zwkU literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/numberpicker_selection_divider.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/numberpicker_selection_divider.9.png new file mode 100644 index 0000000000000000000000000000000000000000..b7a99402eb58c62b821e388e56bc1f24f1e468c6 GIT binary patch literal 217 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqEX7WqAsj$Z!;#Vf4nJ za0`JjKhs88ydXVVch{#VC3oI7$PzCZ2v}H1_gl@xyNqj-bwU5 zl(`WVlccR{vOp|>HN@({jOwKf8&nHFJ0HmY%;5b~Xyr*R;}1aH44$rjF6*2UngIQ1 BKpy}A literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable/item_background_holo_light.xml b/TMessagesProj/src/main/res/drawable/item_background_holo_light.xml new file mode 100644 index 00000000..652dc8a4 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/item_background_holo_light.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/TMessagesProj/src/main/res/drawable/list_selector_background_transition_holo_light.xml b/TMessagesProj/src/main/res/drawable/list_selector_background_transition_holo_light.xml new file mode 100644 index 00000000..41cae09a --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/list_selector_background_transition_holo_light.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/TMessagesProj/src/main/res/values-ar/strings.xml b/TMessagesProj/src/main/res/values-ar/strings.xml index 961caa6d..31cc29be 100644 --- a/TMessagesProj/src/main/res/values-ar/strings.xml +++ b/TMessagesProj/src/main/res/values-ar/strings.xml @@ -118,12 +118,6 @@ لقد قمت بتعيين التدمير الذاتي إلى %1$s %1$s قام بإيقاف عداد التدمير الذاتي لقد قمت بتعطيل عداد التدمير الذاتي - ثانيتان - ٥ ثوانٍ - دقيقة - ساعة - يوم - أسبوع لديك رسالة جديدة %1$s: %2$s %1$s قام بإرسال رسالة لك @@ -202,12 +196,6 @@ مفتاح التشفير عداد التدمير الذاتي إيقاف - ثانيتان - ٥ ثوانٍ - دقيقة - ساعة - يوم - أسبوع هذه الصورة هي تصور لمفتاح التشفير لهذه المحادثة السرية مع ]]>%1$s]]>.
    ]]>إذا كانت مطابقة للصورة التي في جهاز ]]>%2$s]]>, فمحادثتكم آمنة ٢٠٠٪.
    ]]>للمزيد نرجو الذهاب إلى telegram.org
    تم تعيين كافة الإشعارات افتراضيا @@ -434,6 +422,36 @@ من %1$d جهات اتصال من %1$d جهة اتصال من %1$d جهة اتصال + %1$d seconds + %1$d second + %1$d seconds + %1$d seconds + %1$d seconds + %1$d seconds + %1$d minutes + %1$d minute + %1$d minutes + %1$d minutes + %1$d minutes + %1$d minutes + %1$d hours + %1$d hour + %1$d hours + %1$d hours + %1$d hours + %1$d hours + %1$d days + %1$d day + %1$d days + %1$d days + %1$d days + %1$d days + %1$d weeks + %1$d week + %1$d weeks + %1$d weeks + %1$d weeks + %1$d weeks dd MMM dd.MM.yy @@ -444,6 +462,4 @@ HH:mm h:mm a %1$s الساعة %2$s - - CACHE_TAG \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-de/strings.xml b/TMessagesProj/src/main/res/values-de/strings.xml index c6f6c6cc..1f5e3ece 100644 --- a/TMessagesProj/src/main/res/values-de/strings.xml +++ b/TMessagesProj/src/main/res/values-de/strings.xml @@ -118,12 +118,6 @@ Du hast den Selbstzerstörungs-Timer auf %1$s gesetzt %1$s hat den Selbstzerstörungs-Timer deaktivert Du hast den Selbstzerstörungs-Timer deaktivert - 2 Sekunden - 5 Sekunden - 1 Minute - 1 Stunde - 1 Tag - 1 Woche Du hast eine neue Nachricht %1$s: %2$s %1$s hat dir eine Nachricht gesendet @@ -202,12 +196,6 @@ Geheimer Schlüssel Selbstzerstörungs-Timer Aus - 2 Sek. - 5 Sek. - 1 Min. - 1 Std. - 1 Tag - 1 Woche Das ist eine Darstellung des Schlüssels für den Geheimen Chat mit ]]>%1$s]]>.
    ]]>Wenn dieses Bild auf ]]>%2$s\s]]>s Telefon genau so aussieht, ist euer Chat zu 200%% sicher.
    ]]>Erfahre mehr auf telegram.org
    Alle Einstellungen für Mitteilungen zurücksetzen @@ -434,6 +422,36 @@ von %1$d Kontakten von %1$d Kontakten von %1$d Kontakten + %1$d seconds + %1$d second + %1$d seconds + %1$d seconds + %1$d seconds + %1$d seconds + %1$d minutes + %1$d minute + %1$d minutes + %1$d minutes + %1$d minutes + %1$d minutes + %1$d hours + %1$d hour + %1$d hours + %1$d hours + %1$d hours + %1$d hours + %1$d days + %1$d day + %1$d days + %1$d days + %1$d days + %1$d days + %1$d weeks + %1$d week + %1$d weeks + %1$d weeks + %1$d weeks + %1$d weeks dd MMM dd.MM.yy @@ -444,6 +462,4 @@ HH:mm h:mm a %1$s um %2$s - - CACHE_TAG \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-es/strings.xml b/TMessagesProj/src/main/res/values-es/strings.xml index 70f76dec..a305a69f 100644 --- a/TMessagesProj/src/main/res/values-es/strings.xml +++ b/TMessagesProj/src/main/res/values-es/strings.xml @@ -118,12 +118,6 @@ Activaste la autodestrucción en %1$s %1$s desactivó la autodestrucción Desactivaste la autodestrucción - 2 segundos - 5 segundos - 1 minuto - 1 hora - 1 día - 1 semana Tienes un nuevo mensaje %1$s: %2$s %1$s te envió un mensaje @@ -175,7 +169,7 @@ PON EL NOMBRE DEL GRUPO Fotos y vídeos - Información + Información FOTOS Y VÍDEOS AJUSTES Añadir miembro @@ -202,12 +196,6 @@ Clave de cifrado Autodestrucción Apagada - 2s - 5s - 1m - 1h - 1d - 1S Esta imagen es una visualización de la clave de cifrado para el chat secreto con ]]>%1$s]]>.
    ]]>Si esta imagen se ve igual en el teléfono de ]]>%2$s]]>, tu chat es seguro en un 200%%.
    ]]>Aprende más en telegram.org
    Restablecer las notificaciones @@ -267,7 +255,7 @@ Desactivadas Con pantalla encendida Con pantalla apagada - Mostrar siempre + Mostrar siempre Globo en el ícono Corto Largo @@ -434,6 +422,36 @@ de %1$d contactos de %1$d contactos de %1$d contactos + %1$d seconds + %1$d second + %1$d seconds + %1$d seconds + %1$d seconds + %1$d seconds + %1$d minutes + %1$d minute + %1$d minutes + %1$d minutes + %1$d minutes + %1$d minutes + %1$d hours + %1$d hour + %1$d hours + %1$d hours + %1$d hours + %1$d hours + %1$d days + %1$d day + %1$d days + %1$d days + %1$d days + %1$d days + %1$d weeks + %1$d week + %1$d weeks + %1$d weeks + %1$d weeks + %1$d weeks dd \'de\' MMM dd.MM.yy @@ -444,6 +462,4 @@ HH:mm h:mm a %1$s a las %2$s - - CACHE_TAG \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-it/strings.xml b/TMessagesProj/src/main/res/values-it/strings.xml index 23a75066..ab97be9d 100644 --- a/TMessagesProj/src/main/res/values-it/strings.xml +++ b/TMessagesProj/src/main/res/values-it/strings.xml @@ -118,12 +118,6 @@ Hai impostato il timer di autodistruzione a %1$s %1$s ha disabilitato il timer di autodistruzione Hai disabilitato il timer di autodistruzione - 2 secondi - 5 secondi - 1 minuto - 1 ora - 1 giorno - 1 settimana Hai un nuovo messaggio %1$s: %2$s %1$s ti ha inviato un messaggio @@ -202,12 +196,6 @@ Chiave di cifratura Timer di autodistruzione Spento - 2s - 5s - 1m - 1h - 1g - 1sett Questa immagine è una visualizzazione della chiave di cifratura per questa chat segreta con ]]>%1$s]]>.
    ]]>Se questa immagine è uguale sul telefono di ]]>%2$s]]>, la chat è sicura al 200%%.
    ]]>Per saperne di più, visita Telegram.org
    Ripristina tutte le impostazioni di notifica predefinite @@ -434,6 +422,36 @@ da %1$d contatti da %1$d contatti da %1$d contatti + %1$d seconds + %1$d second + %1$d seconds + %1$d seconds + %1$d seconds + %1$d seconds + %1$d minutes + %1$d minute + %1$d minutes + %1$d minutes + %1$d minutes + %1$d minutes + %1$d hours + %1$d hour + %1$d hours + %1$d hours + %1$d hours + %1$d hours + %1$d days + %1$d day + %1$d days + %1$d days + %1$d days + %1$d days + %1$d weeks + %1$d week + %1$d weeks + %1$d weeks + %1$d weeks + %1$d weeks dd MMM dd.MM.yy @@ -444,6 +462,4 @@ HH:mm h:mm a %1$s alle %2$s - - CACHE_TAG \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-ko/strings.xml b/TMessagesProj/src/main/res/values-ko/strings.xml index 754bc210..b17838d1 100644 --- a/TMessagesProj/src/main/res/values-ko/strings.xml +++ b/TMessagesProj/src/main/res/values-ko/strings.xml @@ -118,12 +118,6 @@ 자동삭제를 %1$s 후로 설정했습니다 %1$s님이 자동삭제를 해제했습니다 자동삭제를 해제했습니다 - 2초 - 5초 - 1분 - 1시간 - 하루 - 일주일 새 메시지가 있습니다 %1$s: %2$s %1$s님이 메시지를 보냈습니다 @@ -202,12 +196,6 @@ 암호화 키 자동삭제 타이머 해제 - 2초 - 5초 - 1분 - 1시간 - 하루 - 일주일 이 이미지는 ]]>%1$s]]>님과의 비밀대화에 사용 중인 암호화 키의 모습입니다.
    ]]>이 이미지가 ]]>%2$s]]>님의 암호화 키와 똑같다면 대화는 200%% 안전합니다.
    ]]>더 자세한 사항은 telegram.org 를 참고해 주세요.
    모든 알림 설정이 초기화되었습니다 @@ -434,6 +422,36 @@ 채팅방 %1$d개에서 채팅방 %1$d개에서 채팅방 %1$d개에서 + %1$d seconds + %1$d second + %1$d seconds + %1$d seconds + %1$d seconds + %1$d seconds + %1$d minutes + %1$d minute + %1$d minutes + %1$d minutes + %1$d minutes + %1$d minutes + %1$d hours + %1$d hour + %1$d hours + %1$d hours + %1$d hours + %1$d hours + %1$d days + %1$d day + %1$d days + %1$d days + %1$d days + %1$d days + %1$d weeks + %1$d week + %1$d weeks + %1$d weeks + %1$d weeks + %1$d weeks M\'월\' d\'일\' yyyy.MM.dd. @@ -444,6 +462,4 @@ HH:mm a h:mm %1$s %2$s - - CACHE_TAG \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-nl/strings.xml b/TMessagesProj/src/main/res/values-nl/strings.xml index 6a790bbf..a1461457 100644 --- a/TMessagesProj/src/main/res/values-nl/strings.xml +++ b/TMessagesProj/src/main/res/values-nl/strings.xml @@ -118,12 +118,6 @@ Je hebt de zelfvernietigingstimer ingesteld op %1$s %1$s heeft de zelfvernietigingstimer uitgeschakeld Je hebt de zelfvernietigingstimer uitgeschakeld - 2 seconden - 5 seconden - 1 minuut - 1 uur - 1 dag - 1 week Je hebt een nieuw bericht %1$s: %2$s %1$s heeft je een bericht gestuurd @@ -202,12 +196,6 @@ Encryptiesleutel Zelfvernietigingstimer Uit - 2s - 5s - 1m - 1u - 1d - 1w Dit is een weergave van de encryptiesleutel voor deze geheime chat met ]]>%1$s]]>.
    ]]>Als deze afbeelding er bij ]]>%2$s]]> hetzelfde uitziet, is jullie gesprek 200%% beveiligd.
    ]]>Lees meer op telegram.org.
    Alle meldingsinstellingen herstellen @@ -434,6 +422,36 @@ van %1$d contactpersonen van %1$d contactpersonen van %1$d contactpersonen + %1$d seconds + %1$d second + %1$d seconds + %1$d seconds + %1$d seconds + %1$d seconds + %1$d minutes + %1$d minute + %1$d minutes + %1$d minutes + %1$d minutes + %1$d minutes + %1$d hours + %1$d hour + %1$d hours + %1$d hours + %1$d hours + %1$d hours + %1$d days + %1$d day + %1$d days + %1$d days + %1$d days + %1$d days + %1$d weeks + %1$d week + %1$d weeks + %1$d weeks + %1$d weeks + %1$d weeks dd MMM dd-MM-yy @@ -444,6 +462,4 @@ HH:mm h:mm a %1$s om %2$s - - CACHE_TAG \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml index 8af461b7..ae5634e1 100644 --- a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml @@ -114,16 +114,10 @@ Conversa secreta solicitada Conversa secreta iniciada - %1$s estabeleceu o tempo de autodestruição para %2$s + %1$s estabeleceu o tempo de autodestruição para %2$s Você estabeleceu o tempo de autodestruição para %1$s %1$s desativou o temporizador de autodestruição Você desativou o temporizador de autodestruição - 2 segundos - 5 segundos - 1 minuto - 1 hora - 1 dia - 1 semana Você tem uma nova mensagem %1$s: %2$s %1$s te enviou uma mensagem @@ -202,12 +196,6 @@ Chave criptográfica Tempo de autodestruição Desativado - 2s - 5s - 1m - 1h - 1d - 1 sem. Esta imagem é uma visualização da chave criptográfica para esta conversa secreta com ]]>%1$s]]>.
    ]]>Se esta imagem aparecer da mesma forma no telefone de ]]>%2$s\'s]]>, sua conversa é 200%% segura.
    ]]>Saiba mais em telegram.org
    Restaurar todas as configurações de notificação @@ -434,6 +422,36 @@ de %1$d contatos de %1$d contatos de %1$d contatos + %1$d seconds + %1$d second + %1$d seconds + %1$d seconds + %1$d seconds + %1$d seconds + %1$d minutes + %1$d minute + %1$d minutes + %1$d minutes + %1$d minutes + %1$d minutes + %1$d hours + %1$d hour + %1$d hours + %1$d hours + %1$d hours + %1$d hours + %1$d days + %1$d day + %1$d days + %1$d days + %1$d days + %1$d days + %1$d weeks + %1$d week + %1$d weeks + %1$d weeks + %1$d weeks + %1$d weeks dd MMM dd.MM.yy @@ -444,6 +462,4 @@ HH:mm h:mm a %1$s às %2$s - - CACHE_TAG \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-pt-rPT/strings.xml b/TMessagesProj/src/main/res/values-pt-rPT/strings.xml index 1d089246..90d884f2 100644 --- a/TMessagesProj/src/main/res/values-pt-rPT/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rPT/strings.xml @@ -114,16 +114,10 @@ Conversa secreta solicitada Conversa secreta iniciada - %1$s estabeleceu o tempo de autodestruição para %2$s + %1$s estabeleceu o tempo de autodestruição para %2$s Você estabeleceu o tempo de autodestruição para %1$s %1$s desativou o temporizador de autodestruição Você desativou o temporizador de autodestruição - 2 segundos - 5 segundos - 1 minuto - 1 hora - 1 dia - 1 semana Você tem uma nova mensagem %1$s: %2$s %1$s te enviou uma mensagem @@ -202,12 +196,6 @@ Chave criptográfica Tempo de autodestruição Desativado - 2s - 5s - 1m - 1h - 1d - 1 sem. Esta imagem é uma visualização da chave criptográfica para esta conversa secreta com ]]>%1$s]]>.
    ]]>Se esta imagem aparecer da mesma forma no telefone de ]]>%2$s\'s]]>, sua conversa é 200%% segura.
    ]]>Saiba mais em telegram.org
    Restaurar todas as configurações de notificação @@ -434,6 +422,36 @@ de %1$d contatos de %1$d contatos de %1$d contatos + %1$d seconds + %1$d second + %1$d seconds + %1$d seconds + %1$d seconds + %1$d seconds + %1$d minutes + %1$d minute + %1$d minutes + %1$d minutes + %1$d minutes + %1$d minutes + %1$d hours + %1$d hour + %1$d hours + %1$d hours + %1$d hours + %1$d hours + %1$d days + %1$d day + %1$d days + %1$d days + %1$d days + %1$d days + %1$d weeks + %1$d week + %1$d weeks + %1$d weeks + %1$d weeks + %1$d weeks dd MMM dd.MM.yy @@ -444,6 +462,4 @@ HH:mm h:mm a %1$s às %2$s - - CACHE_TAG \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index b6cd51c4..3dce45be 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -118,12 +118,6 @@ You set the self-destruct timer to %1$s %1$s disabled the self-destruct timer You disabled the self-destruct timer - 2 seconds - 5 seconds - 1 minute - 1 hour - 1 day - 1 week You have a new message %1$s: %2$s %1$s sent you a message @@ -202,12 +196,6 @@ Encryption Key Self-Destruct Timer Off - 2s - 5s - 1m - 1h - 1d - 1w This image is a visualization of the encryption key for this secret chat with ]]>%1$s]]>.
    ]]>If this image looks the same on ]]>%2$s\'s]]> phone, your chat is 200%% secure.
    ]]>Learn more at telegram.org
    Reset all notification settings to default @@ -434,6 +422,36 @@ from %1$d contacts from %1$d contacts from %1$d contacts + %1$d seconds + %1$d second + %1$d seconds + %1$d seconds + %1$d seconds + %1$d seconds + %1$d minutes + %1$d minute + %1$d minutes + %1$d minutes + %1$d minutes + %1$d minutes + %1$d hours + %1$d hour + %1$d hours + %1$d hours + %1$d hours + %1$d hours + %1$d days + %1$d day + %1$d days + %1$d days + %1$d days + %1$d days + %1$d weeks + %1$d week + %1$d weeks + %1$d weeks + %1$d weeks + %1$d weeks MMM dd dd.MM.yy @@ -444,6 +462,4 @@ HH:mm h:mm a %1$s at %2$s - - CACHE_TAG \ No newline at end of file From 288fceeb9fff8084f7c8494d25fea5a6bf73c54a Mon Sep 17 00:00:00 2001 From: DrKLO Date: Wed, 15 Oct 2014 22:43:52 +0400 Subject: [PATCH 07/18] UI improvements --- .../org/telegram/android/MessageObject.java | 66 +- .../org/telegram/messenger/FileLoader.java | 36 +- .../java/org/telegram/ui/Cells/BaseCell.java | 58 ++ .../org/telegram/ui/Cells/ChatActionCell.java | 237 ++++- .../org/telegram/ui/Cells/ChatBaseCell.java | 68 +- .../telegram/ui/Cells/ChatContactCell.java | 271 +++++ .../org/telegram/ui/Cells/ChatMediaCell.java | 6 +- .../java/org/telegram/ui/ChatActivity.java | 972 ++++++------------ .../java/org/telegram/ui/LaunchActivity.java | 11 +- .../telegram/ui/Views/HorizontalListView.java | 8 +- .../ui/Views/MessageActionLayout.java | 42 - .../org/telegram/ui/Views/TightTextView.java | 118 --- .../telegram/ui/Views/URLSpanNoUnderline.java | 24 + .../chat_action_change_photo_layout.xml | 42 - .../res/layout/chat_action_message_layout.xml | 35 - 15 files changed, 921 insertions(+), 1073 deletions(-) create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java delete mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Views/MessageActionLayout.java delete mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Views/TightTextView.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Views/URLSpanNoUnderline.java delete mode 100644 TMessagesProj/src/main/res/layout/chat_action_change_photo_layout.xml delete mode 100644 TMessagesProj/src/main/res/layout/chat_action_message_layout.xml diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java index f6f92394..54fd6579 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java @@ -12,8 +12,11 @@ import android.graphics.Bitmap; import android.graphics.Paint; import android.text.Layout; import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.Spanned; import android.text.StaticLayout; import android.text.TextPaint; +import android.text.TextUtils; import android.text.util.Linkify; import org.telegram.messenger.ConnectionsManager; @@ -22,6 +25,7 @@ import org.telegram.messenger.FileLog; import org.telegram.messenger.TLRPC; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; +import org.telegram.ui.Views.URLSpanNoUnderline; import java.util.AbstractMap; import java.util.ArrayList; @@ -91,7 +95,7 @@ public class MessageObject { messageText = LocaleController.getString("ActionYouCreateGroup", R.string.ActionYouCreateGroup); } else { if (fromUser != null) { - messageText = LocaleController.getString("ActionCreateGroup", R.string.ActionCreateGroup).replace("un1", ContactsController.formatName(fromUser.first_name, fromUser.last_name)); + messageText = replaceWithLink(LocaleController.getString("ActionCreateGroup", R.string.ActionCreateGroup), "un1", fromUser); } else { messageText = LocaleController.getString("ActionCreateGroup", R.string.ActionCreateGroup).replace("un1", ""); } @@ -102,26 +106,27 @@ public class MessageObject { messageText = LocaleController.getString("ActionYouLeftUser", R.string.ActionYouLeftUser); } else { if (fromUser != null) { - messageText = LocaleController.getString("ActionLeftUser", R.string.ActionLeftUser).replace("un1", ContactsController.formatName(fromUser.first_name, fromUser.last_name)); + messageText = replaceWithLink(LocaleController.getString("ActionLeftUser", R.string.ActionLeftUser), "un1", fromUser); } else { messageText = LocaleController.getString("ActionLeftUser", R.string.ActionLeftUser).replace("un1", ""); } } } else { - TLRPC.User who = null; + TLRPC.User whoUser = null; if (users != null) { - who = users.get(message.action.user_id); + whoUser = users.get(message.action.user_id); } - if (who == null) { - who = MessagesController.getInstance().getUser(message.action.user_id); + if (whoUser == null) { + whoUser = MessagesController.getInstance().getUser(message.action.user_id); } - if (who != null && fromUser != null) { + if (whoUser != null && fromUser != null) { if (isFromMe()) { - messageText = LocaleController.getString("ActionYouKickUser", R.string.ActionYouKickUser).replace("un2", ContactsController.formatName(who.first_name, who.last_name)); + messageText = replaceWithLink(LocaleController.getString("ActionYouKickUser", R.string.ActionYouKickUser), "un2", whoUser); } else if (message.action.user_id == UserConfig.getClientUserId()) { - messageText = LocaleController.getString("ActionKickUserYou", R.string.ActionKickUserYou).replace("un1", ContactsController.formatName(fromUser.first_name, fromUser.last_name)); + messageText = replaceWithLink(LocaleController.getString("ActionKickUserYou", R.string.ActionKickUserYou), "un1", fromUser); } else { - messageText = LocaleController.getString("ActionKickUser", R.string.ActionKickUser).replace("un2", ContactsController.formatName(who.first_name, who.last_name)).replace("un1", ContactsController.formatName(fromUser.first_name, fromUser.last_name)); + messageText = replaceWithLink(LocaleController.getString("ActionKickUser", R.string.ActionKickUser), "un2", whoUser); + messageText = replaceWithLink(messageText, "un1", fromUser); } } else { messageText = LocaleController.getString("ActionKickUser", R.string.ActionKickUser).replace("un2", "").replace("un1", ""); @@ -137,11 +142,12 @@ public class MessageObject { } if (whoUser != null && fromUser != null) { if (isFromMe()) { - messageText = LocaleController.getString("ActionYouAddUser", R.string.ActionYouAddUser).replace("un2", ContactsController.formatName(whoUser.first_name, whoUser.last_name)); + messageText = replaceWithLink(LocaleController.getString("ActionYouAddUser", R.string.ActionYouAddUser), "un2", whoUser); } else if (message.action.user_id == UserConfig.getClientUserId()) { - messageText = LocaleController.getString("ActionAddUserYou", R.string.ActionAddUserYou).replace("un1", ContactsController.formatName(fromUser.first_name, fromUser.last_name)); + messageText = replaceWithLink(LocaleController.getString("ActionAddUserYou", R.string.ActionAddUserYou), "un1", fromUser); } else { - messageText = LocaleController.getString("ActionAddUser", R.string.ActionAddUser).replace("un2", ContactsController.formatName(whoUser.first_name, whoUser.last_name)).replace("un1", ContactsController.formatName(fromUser.first_name, fromUser.last_name)); + messageText = replaceWithLink(LocaleController.getString("ActionAddUser", R.string.ActionAddUser), "un2", whoUser); + messageText = replaceWithLink(messageText, "un1", fromUser); } } else { messageText = LocaleController.getString("ActionAddUser", R.string.ActionAddUser).replace("un2", "").replace("un1", ""); @@ -151,7 +157,7 @@ public class MessageObject { messageText = LocaleController.getString("ActionYouChangedPhoto", R.string.ActionYouChangedPhoto); } else { if (fromUser != null) { - messageText = LocaleController.getString("ActionChangedPhoto", R.string.ActionChangedPhoto).replace("un1", ContactsController.formatName(fromUser.first_name, fromUser.last_name)); + messageText = replaceWithLink(LocaleController.getString("ActionChangedPhoto", R.string.ActionChangedPhoto), "un1", fromUser); } else { messageText = LocaleController.getString("ActionChangedPhoto", R.string.ActionChangedPhoto).replace("un1", ""); } @@ -161,7 +167,7 @@ public class MessageObject { messageText = LocaleController.getString("ActionYouChangedTitle", R.string.ActionYouChangedTitle).replace("un2", message.action.title); } else { if (fromUser != null) { - messageText = LocaleController.getString("ActionChangedTitle", R.string.ActionChangedTitle).replace("un1", ContactsController.formatName(fromUser.first_name, fromUser.last_name)).replace("un2", message.action.title); + messageText = replaceWithLink(LocaleController.getString("ActionChangedTitle", R.string.ActionChangedTitle).replace("un2", message.action.title), "un1", fromUser); } else { messageText = LocaleController.getString("ActionChangedTitle", R.string.ActionChangedTitle).replace("un1", "").replace("un2", message.action.title); } @@ -171,7 +177,7 @@ public class MessageObject { messageText = LocaleController.getString("ActionYouRemovedPhoto", R.string.ActionYouRemovedPhoto); } else { if (fromUser != null) { - messageText = LocaleController.getString("ActionRemovedPhoto", R.string.ActionRemovedPhoto).replace("un1", ContactsController.formatName(fromUser.first_name, fromUser.last_name)); + messageText = replaceWithLink(LocaleController.getString("ActionRemovedPhoto", R.string.ActionRemovedPhoto), "un1", fromUser); } else { messageText = LocaleController.getString("ActionRemovedPhoto", R.string.ActionRemovedPhoto).replace("un1", ""); } @@ -232,7 +238,7 @@ public class MessageObject { messageText = LocaleController.formatString("ActionTakeScreenshootYou", R.string.ActionTakeScreenshootYou); } else { if (fromUser != null) { - messageText = LocaleController.formatString("ActionTakeScreenshoot", R.string.ActionTakeScreenshoot).replace("un1", fromUser.first_name); + messageText = replaceWithLink(LocaleController.getString("ActionTakeScreenshoot", R.string.ActionTakeScreenshoot), "un1", fromUser); } else { messageText = LocaleController.formatString("ActionTakeScreenshoot", R.string.ActionTakeScreenshoot).replace("un1", ""); } @@ -263,7 +269,7 @@ public class MessageObject { } messageText = Emoji.replaceEmoji(messageText, textPaint.getFontMetricsInt(), AndroidUtilities.dp(20)); - if (message instanceof TLRPC.TL_message || (message instanceof TLRPC.TL_messageForwarded && (message.media == null || !(message.media instanceof TLRPC.TL_messageMediaEmpty)))) { + if (message instanceof TLRPC.TL_message || message instanceof TLRPC.TL_messageForwarded) { if (message.media == null || message.media instanceof TLRPC.TL_messageMediaEmpty) { contentType = type = 0; } else if (message.media != null && message.media instanceof TLRPC.TL_messageMediaPhoto) { @@ -275,13 +281,8 @@ public class MessageObject { contentType = 1; type = 3; } else if (message.media != null && message.media instanceof TLRPC.TL_messageMediaContact) { - if (isFromMe()) { - contentType = 3; - type = 12; - } else { - contentType = 4; - type = 13; - } + contentType = 3; + type = 12; } else if (message.media != null && message.media instanceof TLRPC.TL_messageMediaUnsupported) { contentType = type = 0; } else if (message.media != null && message.media instanceof TLRPC.TL_messageMediaDocument) { @@ -298,14 +299,12 @@ public class MessageObject { if (message.action instanceof TLRPC.TL_messageActionLoginUnknownLocation) { contentType = type = 0; } else if (message.action instanceof TLRPC.TL_messageActionChatEditPhoto || message.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) { - contentType = 8; + contentType = 4; type = 11; } else { - contentType = 7; + contentType = 4; type = 10; } - } else if (message instanceof TLRPC.TL_messageForwarded) { - contentType = type = 0; } Calendar rightNow = new GregorianCalendar(); @@ -319,6 +318,15 @@ public class MessageObject { generateThumbs(false, preview); } + public CharSequence replaceWithLink(CharSequence source, String param, TLRPC.User user) { + String name = ContactsController.formatName(user.first_name, user.last_name); + int start = TextUtils.indexOf(source, param); + URLSpanNoUnderline span = new URLSpanNoUnderline("" + user.id); + SpannableStringBuilder builder = new SpannableStringBuilder(TextUtils.replace(source, new String[]{param}, new String[]{name})); + builder.setSpan(span, start, start + name.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + return builder; + } + public void generateThumbs(boolean update, int preview) { if (messageOwner instanceof TLRPC.TL_messageService) { if (messageOwner.action instanceof TLRPC.TL_messageActionChatEditPhoto) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java index 4d45efa6..f67e955f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java @@ -564,18 +564,30 @@ public class FileLoader { if (message == null) { return new File(""); } - if (message.media instanceof TLRPC.TL_messageMediaVideo) { - return getPathToAttach(message.media.video); - } else if (message.media instanceof TLRPC.TL_messageMediaDocument) { - return getPathToAttach(message.media.document); - } else if (message.media instanceof TLRPC.TL_messageMediaAudio) { - return getPathToAttach(message.media.audio); - } else if (message.media instanceof TLRPC.TL_messageMediaPhoto) { - ArrayList sizes = message.media.photo.sizes; - if (sizes.size() > 0) { - TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize()); - if (sizeFull != null) { - return getPathToAttach(sizeFull); + if (message instanceof TLRPC.TL_messageService) { + if (message.action.photo != null) { + ArrayList sizes = message.action.photo.sizes; + if (sizes.size() > 0) { + TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize()); + if (sizeFull != null) { + return getPathToAttach(sizeFull); + } + } + } + } else { + if (message.media instanceof TLRPC.TL_messageMediaVideo) { + return getPathToAttach(message.media.video); + } else if (message.media instanceof TLRPC.TL_messageMediaDocument) { + return getPathToAttach(message.media.document); + } else if (message.media instanceof TLRPC.TL_messageMediaAudio) { + return getPathToAttach(message.media.audio); + } else if (message.media instanceof TLRPC.TL_messageMediaPhoto) { + ArrayList sizes = message.media.photo.sizes; + if (sizes.size() > 0) { + TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize()); + if (sizeFull != null) { + return getPathToAttach(sizeFull); + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/BaseCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/BaseCell.java index d5eb4998..c0170b66 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/BaseCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/BaseCell.java @@ -10,10 +10,43 @@ package org.telegram.ui.Cells; import android.content.Context; import android.graphics.drawable.Drawable; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; import android.view.View; +import android.view.ViewConfiguration; public class BaseCell extends View { + private final class CheckForTap implements Runnable { + public void run() { + if (pendingCheckForLongPress == null) { + pendingCheckForLongPress = new CheckForLongPress(); + } + pendingCheckForLongPress.currentPressCount = ++pressCount; + postDelayed(pendingCheckForLongPress, ViewConfiguration.getLongPressTimeout() - ViewConfiguration.getTapTimeout()); + } + } + + class CheckForLongPress implements Runnable { + public int currentPressCount; + + public void run() { + if (checkingForLongPress && getParent() != null && currentPressCount == pressCount) { + checkingForLongPress = false; + MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0); + onTouchEvent(event); + event.recycle(); + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + onLongPress(); + } + } + } + + private boolean checkingForLongPress = false; + private CheckForLongPress pendingCheckForLongPress = null; + private int pressCount = 0; + private CheckForTap pendingCheckForTap = null; + public BaseCell(Context context) { super(context); } @@ -25,4 +58,29 @@ public class BaseCell extends View { protected void setDrawableBounds(Drawable drawable, int x, int y, int w, int h) { drawable.setBounds(x, y, x + w, y + h); } + + protected void startCheckLongPress() { + if (checkingForLongPress) { + return; + } + checkingForLongPress = true; + if (pendingCheckForTap == null) { + pendingCheckForTap = new CheckForTap(); + } + postDelayed(pendingCheckForTap, ViewConfiguration.getTapTimeout()); + } + + protected void cancelCheckLongPress() { + checkingForLongPress = false; + if (pendingCheckForLongPress != null) { + removeCallbacks(pendingCheckForLongPress); + } + if (pendingCheckForTap != null) { + removeCallbacks(pendingCheckForTap); + } + } + + protected void onLongPress() { + + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java index b9ec3da6..7dd0b4c9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java @@ -9,36 +9,58 @@ package org.telegram.ui.Cells; import android.content.Context; +import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.text.Layout; +import android.text.Spannable; import android.text.StaticLayout; import android.text.TextPaint; +import android.text.style.URLSpan; +import android.view.MotionEvent; +import android.view.SoundEffectConstants; import org.telegram.android.AndroidUtilities; +import org.telegram.android.ImageReceiver; import org.telegram.android.MessageObject; import org.telegram.android.MessagesController; +import org.telegram.android.PhotoObject; import org.telegram.messenger.FileLog; import org.telegram.messenger.R; +import org.telegram.messenger.TLRPC; +import org.telegram.messenger.UserConfig; +import org.telegram.ui.PhotoViewer; public class ChatActionCell extends BaseCell { + public static interface ChatActionCellDelegate { + public abstract void didClickedImage(ChatActionCell cell); + public abstract void didLongPressed(ChatActionCell cell); + public abstract void needOpenUserProfile(int uid); + } + private static Drawable backgroundBlack; private static Drawable backgroundBlue; private static TextPaint textPaint; + private URLSpan pressedLink; + + private ImageReceiver imageReceiver; private StaticLayout textLayout; private int textWidth = 0; private int textHeight = 0; private int textX = 0; - private int textXLeft = 0; private int textY = 0; + private int textXLeft = 0; private boolean useBlackBackground = false; - private boolean wasLayout = false; + private int previousWidth = 0; + private boolean imagePressed = false; private MessageObject currentMessageObject; + private ChatActionCellDelegate delegate; + public ChatActionCell(Context context) { super(context); if (backgroundBlack == null) { @@ -47,49 +69,52 @@ public class ChatActionCell extends BaseCell { textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); textPaint.setColor(0xffffffff); + textPaint.linkColor = 0xffffffff; } + imageReceiver = new ImageReceiver(this); textPaint.setTextSize(AndroidUtilities.dp(MessagesController.getInstance().fontSize)); } + public void setDelegate(ChatActionCellDelegate delegate) { + this.delegate = delegate; + } + public void setMessageObject(MessageObject messageObject) { if (currentMessageObject == messageObject) { return; } currentMessageObject = messageObject; - int size; - if (AndroidUtilities.isTablet()) { - size = AndroidUtilities.getMinTabletSide(); - } else { - size = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y); - } - textLayout = new StaticLayout(currentMessageObject.messageText, textPaint, size - AndroidUtilities.dp(30), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); - textHeight = 0; - textWidth = 0; - try { - int linesCount = textLayout.getLineCount(); - boolean hasNonRTL = false; - for (int a = 0; a < linesCount; a++) { - float lineWidth = 0; - float lineLeft = 0; - try { - lineWidth = textLayout.getLineWidth(a); - lineLeft = textLayout.getLineLeft(a); - textHeight = (int)Math.max(textHeight, Math.ceil(textLayout.getLineBottom(a))); - } catch (Exception e) { - FileLog.e("tmessages", e); - return; + previousWidth = 0; + if (currentMessageObject.type == 11) { + int id = 0; + if (messageObject.messageOwner.to_id != null) { + if (messageObject.messageOwner.to_id.chat_id != 0) { + id = messageObject.messageOwner.to_id.chat_id; + } else { + id = messageObject.messageOwner.to_id.user_id; + if (id == UserConfig.getClientUserId()) { + id = messageObject.messageOwner.from_id; + } } - - if (lineLeft == 0) { - hasNonRTL = true; - } - textWidth = (int)Math.max(textWidth, Math.ceil(lineWidth)); } - } catch (Exception e) { - FileLog.e("tmessages", e); + if (currentMessageObject.messageOwner.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) { + imageReceiver.setImage(currentMessageObject.messageOwner.action.newUserPhoto.photo_small, "50_50", getResources().getDrawable(AndroidUtilities.getUserAvatarForId(id)), false); + } else { + PhotoObject photo = PhotoObject.getClosestImageWithSize(currentMessageObject.photoThumbs, AndroidUtilities.dp(64)); + if (photo != null) { + if (photo.image != null) { + imageReceiver.setImageBitmap(photo.image); + } else { + imageReceiver.setImage(photo.photoOwner.location, "50_50", getResources().getDrawable(AndroidUtilities.getGroupAvatarForId(id)), false); + } + } else { + imageReceiver.setImageBitmap(getResources().getDrawable(AndroidUtilities.getGroupAvatarForId(id))); + } + } + imageReceiver.setVisible(!PhotoViewer.getInstance().isShowingImage(currentMessageObject), false); + } else { + imageReceiver.setImageBitmap((Bitmap)null); } - textY = AndroidUtilities.dp(7); - wasLayout = false; requestLayout(); } @@ -97,23 +122,141 @@ public class ChatActionCell extends BaseCell { useBlackBackground = value; } - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), textHeight + AndroidUtilities.dp(14)); + public MessageObject getMessageObject() { + return currentMessageObject; + } + + public ImageReceiver getPhotoImage() { + return imageReceiver; } @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + protected void onLongPress() { + if (delegate != null) { + delegate.didLongPressed(this); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + float x = event.getX(); + float y = event.getY(); + + boolean result = false; + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (delegate != null) { + if (currentMessageObject.type == 11 && imageReceiver.isInsideImage(x, y)) { + imagePressed = true; + result = true; + } + if (result) { + startCheckLongPress(); + } + } + } else { + if (event.getAction() != MotionEvent.ACTION_MOVE) { + cancelCheckLongPress(); + } + if (imagePressed) { + if (event.getAction() == MotionEvent.ACTION_UP) { + imagePressed = false; + if (delegate != null) { + delegate.didClickedImage(this); + playSoundEffect(SoundEffectConstants.CLICK); + } + } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { + imagePressed = false; + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + if (!imageReceiver.isInsideImage(x, y)) { + imagePressed = false; + } + } + } + } + if (!result) { + if (event.getAction() == MotionEvent.ACTION_DOWN || pressedLink != null && event.getAction() == MotionEvent.ACTION_UP) { + if (x >= textX && y >= textY && x <= textX + textWidth && y <= textY + textHeight) { + y -= textY; + x -= textXLeft; + + final int line = textLayout.getLineForVertical((int)y); + final int off = textLayout.getOffsetForHorizontal(line, x); + final float left = textLayout.getLineLeft(line); + if (left <= x && left + textLayout.getLineWidth(line) >= x) { + Spannable buffer = (Spannable)currentMessageObject.messageText; + URLSpan[] link = buffer.getSpans(off, off, URLSpan.class); + + if (link.length != 0) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + pressedLink = link[0]; + result = true; + } else { + if (link[0] == pressedLink) { + if (delegate != null) { + delegate.needOpenUserProfile(Integer.parseInt(link[0].getURL())); + } + result = true; + } + } + } else { + pressedLink = null; + } + } else { + pressedLink = null; + } + } else { + pressedLink = null; + } + } + } + + if (!result) { + result = super.onTouchEvent(event); + } + + return result; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (currentMessageObject == null) { - super.onLayout(changed, left, top, right, bottom); + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), textHeight + AndroidUtilities.dp(14)); return; } - if (!wasLayout || changed) { - textX = (right - left - textWidth) / 2; - textXLeft = (right - left - textLayout.getWidth()) / 2; + int width = MeasureSpec.getSize(widthMeasureSpec); + if (width != previousWidth) { + previousWidth = width; - wasLayout = true; + textLayout = new StaticLayout(currentMessageObject.messageText, textPaint, width - AndroidUtilities.dp(30), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); + textHeight = 0; + textWidth = 0; + try { + int linesCount = textLayout.getLineCount(); + for (int a = 0; a < linesCount; a++) { + float lineWidth = 0; + float lineLeft = 0; + try { + lineWidth = textLayout.getLineWidth(a); + textHeight = (int)Math.max(textHeight, Math.ceil(textLayout.getLineBottom(a))); + } catch (Exception e) { + FileLog.e("tmessages", e); + return; + } + textWidth = (int)Math.max(textWidth, Math.ceil(lineWidth)); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + textX = (width - textWidth) / 2; + textY = AndroidUtilities.dp(7); + textXLeft = (width - textLayout.getWidth()) / 2; + + if (currentMessageObject.type == 11) { + imageReceiver.setImageCoords((width - AndroidUtilities.dp(64)) / 2, textHeight + AndroidUtilities.dp(15), AndroidUtilities.dp(64), AndroidUtilities.dp(64)); + } } + setMeasuredDimension(width, textHeight + AndroidUtilities.dp(14 + (currentMessageObject.type == 11 ? 70 : 0))); } @Override @@ -121,10 +264,6 @@ public class ChatActionCell extends BaseCell { if (currentMessageObject == null) { return; } - if (!wasLayout) { - requestLayout(); - return; - } Drawable backgroundDrawable = null; if (useBlackBackground) { @@ -132,9 +271,13 @@ public class ChatActionCell extends BaseCell { } else { backgroundDrawable = backgroundBlue; } - backgroundDrawable.setBounds(textX - AndroidUtilities.dp(5), AndroidUtilities.dp(5), textX + textWidth + AndroidUtilities.dp(5), getMeasuredHeight() - AndroidUtilities.dp(5)); + backgroundDrawable.setBounds(textX - AndroidUtilities.dp(5), AndroidUtilities.dp(5), textX + textWidth + AndroidUtilities.dp(5), AndroidUtilities.dp(9) + textHeight); backgroundDrawable.draw(canvas); + if (currentMessageObject.type == 11) { + imageReceiver.draw(canvas, imageReceiver.getImageX(), imageReceiver.getImageY(), imageReceiver.getImageWidth(), imageReceiver.getImageHeight()); + } + canvas.save(); canvas.translate(textXLeft, textY); textLayout.draw(canvas); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java index 5d99a660..e3e55f58 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java @@ -17,10 +17,8 @@ import android.text.Layout; import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; -import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.SoundEffectConstants; -import android.view.ViewConfiguration; import org.telegram.android.AndroidUtilities; import org.telegram.android.ContactsController; @@ -108,45 +106,13 @@ public class ChatBaseCell extends BaseCell { private TLRPC.User currentForwardUser; private String currentForwardNameString; - public ChatBaseCellDelegate delegate; + protected ChatBaseCellDelegate delegate; protected int namesOffset = 0; - private boolean checkingForLongPress = false; - private int pressCount = 0; - private CheckForLongPress pendingCheckForLongPress = null; - private CheckForTap pendingCheckForTap = null; - private int last_send_state = 0; private int last_delete_date = 0; - private final class CheckForTap implements Runnable { - public void run() { - if (pendingCheckForLongPress == null) { - pendingCheckForLongPress = new CheckForLongPress(); - } - pendingCheckForLongPress.currentPressCount = ++pressCount; - postDelayed(pendingCheckForLongPress, ViewConfiguration.getLongPressTimeout() - ViewConfiguration.getTapTimeout()); - } - } - - class CheckForLongPress implements Runnable { - public int currentPressCount; - - public void run() { - if (checkingForLongPress && getParent() != null && currentPressCount == pressCount) { - if (delegate != null) { - checkingForLongPress = false; - MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0); - onTouchEvent(event); - event.recycle(); - performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - delegate.didLongPressed(ChatBaseCell.this); - } - } - } - } - public ChatBaseCell(Context context) { super(context); if (backgroundDrawableIn == null) { @@ -203,6 +169,10 @@ public class ChatBaseCell extends BaseCell { invalidate(); } + public void setDelegate(ChatBaseCellDelegate delegate) { + this.delegate = delegate; + } + public void setCheckPressed(boolean value, boolean pressed) { isCheckPressed = value; isPressed = pressed; @@ -345,27 +315,6 @@ public class ChatBaseCell extends BaseCell { return backgroundWidth - AndroidUtilities.dp(8); } - protected void startCheckLongPress() { - if (checkingForLongPress) { - return; - } - checkingForLongPress = true; - if (pendingCheckForTap == null) { - pendingCheckForTap = new CheckForTap(); - } - postDelayed(pendingCheckForTap, ViewConfiguration.getTapTimeout()); - } - - protected void cancelCheckLongPress() { - checkingForLongPress = false; - if (pendingCheckForLongPress != null) { - removeCallbacks(pendingCheckForLongPress); - } - if (pendingCheckForTap != null) { - removeCallbacks(pendingCheckForTap); - } - } - @Override public boolean onTouchEvent(MotionEvent event) { boolean result = false; @@ -462,6 +411,13 @@ public class ChatBaseCell extends BaseCell { } + @Override + protected void onLongPress() { + if (delegate != null) { + delegate.didLongPressed(this); + } + } + @Override protected void onDraw(Canvas canvas) { if (currentMessageObject == null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java new file mode 100644 index 00000000..19d7da81 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java @@ -0,0 +1,271 @@ +/* + * This is the source code of Telegram for Android v. 1.7.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2014. + */ + +package org.telegram.ui.Cells; + +import android.content.Context; + +public class ChatContactCell extends ChatBaseCell { + + public ChatContactCell(Context context) { + super(context); + } + + /* + public class ChatListRowHolderEx { + public BackupImageView avatarImageView; + public TextView nameTextView; + public TextView messageTextView; + public TextView timeTextView; + public ImageView halfCheckImage; + public ImageView checkImage; + public MessageObject message; + public TextView phoneTextView; + public BackupImageView contactAvatar; + public View contactView; + public ImageView addContactButton; + public View addContactView; + public View chatBubbleView; + + public void update() { + TLRPC.User fromUser = MessagesController.getInstance().getUser(message.messageOwner.from_id); + + int type = message.type; + + if (timeTextView != null) { + timeTextView.setText(LocaleController.formatterDay.format((long) (message.messageOwner.date) * 1000)); + } + + if (avatarImageView != null && fromUser != null) { + TLRPC.FileLocation photo = null; + if (fromUser.photo != null) { + photo = fromUser.photo.photo_small; + } + int placeHolderId = AndroidUtilities.getUserAvatarForId(fromUser.id); + avatarImageView.setImage(photo, "50_50", placeHolderId); + } + + if (type != 12 && type != 13 && nameTextView != null && fromUser != null && type != 8 && type != 9) { + nameTextView.setText(ContactsController.formatName(fromUser.first_name, fromUser.last_name)); + nameTextView.setTextColor(AndroidUtilities.getColorForId(message.messageOwner.from_id)); + } + + if (type == 12 || type == 13) { + TLRPC.User contactUser = MessagesController.getInstance().getUser(message.messageOwner.media.user_id); + if (contactUser != null) { + nameTextView.setText(ContactsController.formatName(message.messageOwner.media.first_name, message.messageOwner.media.last_name)); + nameTextView.setTextColor(AndroidUtilities.getColorForId(contactUser.id)); + String phone = message.messageOwner.media.phone_number; + if (phone != null && phone.length() != 0) { + if (!phone.startsWith("+")) { + phone = "+" + phone; + } + phoneTextView.setText(PhoneFormat.getInstance().format(phone)); + } else { + phoneTextView.setText("Unknown"); + } + TLRPC.FileLocation photo = null; + if (contactUser.photo != null) { + photo = contactUser.photo.photo_small; + } + int placeHolderId = AndroidUtilities.getUserAvatarForId(contactUser.id); + contactAvatar.setImage(photo, "50_50", placeHolderId); + if (contactUser.id != UserConfig.getClientUserId() && ContactsController.getInstance().contactsDict.get(contactUser.id) == null) { + addContactView.setVisibility(View.VISIBLE); + } else { + addContactView.setVisibility(View.GONE); + } + } else { + nameTextView.setText(ContactsController.formatName(message.messageOwner.media.first_name, message.messageOwner.media.last_name)); + nameTextView.setTextColor(AndroidUtilities.getColorForId(message.messageOwner.media.user_id)); + String phone = message.messageOwner.media.phone_number; + if (phone != null && phone.length() != 0) { + if (message.messageOwner.media.user_id != 0 && !phone.startsWith("+")) { + phone = "+" + phone; + } + phoneTextView.setText(PhoneFormat.getInstance().format(phone)); + } else { + phoneTextView.setText("Unknown"); + } + contactAvatar.setImageResource(AndroidUtilities.getUserAvatarForId(message.messageOwner.media.user_id)); + addContactView.setVisibility(View.GONE); + } + } else if (type == 6) { + messageTextView.setTextSize(16); + messageTextView.setText(LocaleController.formatPluralString("NewMessages", unread_to_load)); + } + + if (message.isFromMe()) { + if (halfCheckImage != null) { + if (message.isSending()) { + checkImage.setVisibility(View.INVISIBLE); + halfCheckImage.setImageResource(R.drawable.msg_clock); + halfCheckImage.setVisibility(View.VISIBLE); + } else if (message.isSendError()) { + halfCheckImage.setVisibility(View.VISIBLE); + halfCheckImage.setImageResource(R.drawable.msg_warning); + if (checkImage != null) { + checkImage.setVisibility(View.INVISIBLE); + } + } else if (message.isSent()) { + if (!message.isUnread()) { + halfCheckImage.setVisibility(View.VISIBLE); + checkImage.setVisibility(View.VISIBLE); + halfCheckImage.setImageResource(R.drawable.msg_halfcheck); + } else { + halfCheckImage.setVisibility(View.VISIBLE); + checkImage.setVisibility(View.INVISIBLE); + halfCheckImage.setImageResource(R.drawable.msg_check); + } + } + } + } + } + + public ChatListRowHolderEx(View view, int type) { + avatarImageView = (BackupImageView)view.findViewById(R.id.chat_group_avatar_image); + nameTextView = (TextView)view.findViewById(R.id.chat_user_group_name); + timeTextView = (TextView)view.findViewById(R.id.chat_time_text); + halfCheckImage = (ImageView)view.findViewById(R.id.chat_row_halfcheck); + checkImage = (ImageView)view.findViewById(R.id.chat_row_check); + messageTextView = (TextView)view.findViewById(R.id.chat_message_text); + phoneTextView = (TextView)view.findViewById(R.id.phone_text_view); + contactAvatar = (BackupImageView)view.findViewById(R.id.contact_avatar); + contactView = view.findViewById(R.id.shared_layout); + addContactButton = (ImageView)view.findViewById(R.id.add_contact_button); + addContactView = view.findViewById(R.id.add_contact_view); + chatBubbleView = view.findViewById(R.id.chat_bubble_layout); + if (messageTextView != null) { + messageTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, MessagesController.getInstance().fontSize); + } + + if (addContactButton != null) { + addContactButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (actionBarLayer.isActionModeShowed()) { + processRowSelect(view); + return; + } + Bundle args = new Bundle(); + args.putInt("user_id", message.messageOwner.media.user_id); + args.putString("phone", message.messageOwner.media.phone_number); + presentFragment(new ContactAddActivity(args)); + } + }); + + addContactButton.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + createMenu(v, false); + return true; + } + }); + } + + if (contactView != null) { + contactView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (message.type == 12 || message.type == 13) { + if (actionBarLayer.isActionModeShowed()) { + processRowSelect(view); + return; + } + if (message.messageOwner.media.user_id != UserConfig.getClientUserId()) { + TLRPC.User user = null; + if (message.messageOwner.media.user_id != 0) { + user = MessagesController.getInstance().getUser(message.messageOwner.media.user_id); + } + if (user != null) { + Bundle args = new Bundle(); + args.putInt("user_id", message.messageOwner.media.user_id); + presentFragment(new UserProfileActivity(args)); + } else { + if (message.messageOwner.media.phone_number == null || message.messageOwner.media.phone_number.length() == 0) { + return; + } + if (getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setItems(new CharSequence[] {LocaleController.getString("Copy", R.string.Copy), LocaleController.getString("Call", R.string.Call)}, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (i == 1) { + try { + Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + message.messageOwner.media.phone_number)); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + getParentActivity().startActivity(intent); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } else if (i == 0) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + android.text.ClipboardManager clipboard = (android.text.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + clipboard.setText(message.messageOwner.media.phone_number); + } else { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText("label", message.messageOwner.media.phone_number); + clipboard.setPrimaryClip(clip); + } + } + } + } + ); + showAlertDialog(builder); + } + } + } + } + }); + + contactView.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + createMenu(v, false); + return true; + } + }); + } + + if (contactAvatar != null) { + contactAvatar.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + + } + }); + } + + if (avatarImageView != null) { + avatarImageView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (actionBarLayer.isActionModeShowed()) { + processRowSelect(view); + return; + } + if (message != null) { + Bundle args = new Bundle(); + args.putInt("user_id", message.messageOwner.from_id); + presentFragment(new UserProfileActivity(args)); + } + } + }); + } + } + + private void processOnClick(View view) { + if (actionBarLayer.isActionModeShowed()) { + processRowSelect(view); + } + } + } + */ +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java index 467f0371..f7310955 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java @@ -93,7 +93,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD private int nameWidth = 0; private String currentNameString; - public ChatMediaCellDelegate mediaDelegate = null; + private ChatMediaCellDelegate mediaDelegate = null; private float currentProgress = 0; private RectF progressRect = new RectF(); @@ -165,6 +165,10 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD } } + public void setMediaDelegate(ChatMediaCellDelegate delegate) { + this.mediaDelegate = delegate; + } + @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 2fb13499..2096f86d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -33,13 +33,11 @@ import android.provider.MediaStore; import android.text.Html; import android.text.TextUtils; import android.util.SparseArray; -import android.util.TypedValue; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.view.ViewParent; import android.view.ViewTreeObserver; import android.webkit.MimeTypeMap; import android.widget.AbsListView; @@ -64,7 +62,6 @@ import org.telegram.messenger.TLRPC; import org.telegram.android.ContactsController; import org.telegram.messenger.FileLog; import org.telegram.android.MessageObject; -import org.telegram.android.PhotoObject; import org.telegram.messenger.ConnectionsManager; import org.telegram.android.MessagesController; import org.telegram.android.NotificationCenter; @@ -75,9 +72,11 @@ import org.telegram.ui.Adapters.BaseFragmentAdapter; import org.telegram.ui.Cells.ChatActionCell; import org.telegram.ui.Cells.ChatAudioCell; import org.telegram.ui.Cells.ChatBaseCell; +import org.telegram.ui.Cells.ChatContactCell; import org.telegram.ui.Cells.ChatMediaCell; import org.telegram.ui.Cells.ChatMessageCell; import org.telegram.ui.Views.ActionBar.ActionBarLayer; +import org.telegram.ui.Views.ActionBar.ActionBarLayout; import org.telegram.ui.Views.ActionBar.ActionBarMenu; import org.telegram.ui.Views.ActionBar.ActionBarMenuItem; import org.telegram.ui.Views.BackupImageView; @@ -85,7 +84,6 @@ import org.telegram.ui.Views.ActionBar.BaseFragment; import org.telegram.ui.Views.ChatActivityEnterView; import org.telegram.android.ImageReceiver; import org.telegram.ui.Views.LayoutListView; -import org.telegram.ui.Views.MessageActionLayout; import org.telegram.ui.Views.SizeNotifierRelativeLayout; import org.telegram.ui.Views.TimerButton; import org.telegram.ui.Views.TypingDotsDrawable; @@ -97,8 +95,7 @@ import java.util.HashMap; import java.util.concurrent.Semaphore; public class ChatActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, MessagesActivity.MessagesActivityDelegate, - DocumentSelectActivity.DocumentSelectActivityDelegate, PhotoViewer.PhotoViewerProvider, PhotoPickerActivity.PhotoPickerActivityDelegate, - VideoEditorActivity.VideoEditorActivityDelegate, LocationActivity.LocationActivityDelegate { + PhotoViewer.PhotoViewerProvider { private TLRPC.Chat currentChat; private TLRPC.User currentUser; @@ -470,7 +467,23 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else if (id == attach_gallery) { PhotoPickerActivity fragment = new PhotoPickerActivity(); - fragment.setDelegate(ChatActivity.this); + fragment.setDelegate(new PhotoPickerActivity.PhotoPickerActivityDelegate() { + @Override + public void didSelectPhotos(ArrayList photos) { + processSendingPhotos(photos, null); + } + + @Override + public void startPhotoSelectActivity() { + try { + Intent photoPickerIntent = new Intent(Intent.ACTION_PICK); + photoPickerIntent.setType("image/*"); + startActivityForResult(photoPickerIntent, 1); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); presentFragment(fragment); } else if (id == attach_video) { try { @@ -499,11 +512,39 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } LocationActivity fragment = new LocationActivity(); - fragment.setDelegate(ChatActivity.this); + fragment.setDelegate(new LocationActivity.LocationActivityDelegate() { + @Override + public void didSelectLocation(double latitude, double longitude) { + SendMessagesHelper.getInstance().sendMessage(latitude, longitude, dialog_id); + if (chatListView != null) { + chatListView.setSelectionFromTop(messages.size() - 1, -100000 - chatListView.getPaddingTop()); + } + if (paused) { + scrollToTopOnResume = true; + } + } + }); presentFragment(fragment); } else if (id == attach_document) { DocumentSelectActivity fragment = new DocumentSelectActivity(); - fragment.setDelegate(ChatActivity.this); + fragment.setDelegate(new DocumentSelectActivity.DocumentSelectActivityDelegate() { + @Override + public void didSelectFile(DocumentSelectActivity activity, String path) { + activity.finishFragment(); + processSendingDocument(path, path); + } + + @Override + public void startDocumentSelectActivity() { + try { + Intent photoPickerIntent = new Intent(Intent.ACTION_PICK); + photoPickerIntent.setType("*/*"); + startActivityForResult(photoPickerIntent, 21); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); presentFragment(fragment); } else if (id == chat_menu_avatar) { if (currentUser != null) { @@ -1292,16 +1333,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void processRowSelect(View view) { - View parentView = getRowParentView(view); - if (parentView == null) { - return; - } MessageObject message = null; if (view instanceof ChatBaseCell) { message = ((ChatBaseCell)view).getMessageObject(); - } else { - ChatListRowHolderEx holder = (ChatListRowHolderEx)parentView.getTag(); - message = holder.message; + } else if (view instanceof ChatActionCell) { + message = ((ChatActionCell)view).getMessageObject(); } int type = getMessageType(message); @@ -1375,6 +1411,25 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + private void setTypingAnimation(boolean start) { + if (actionBarLayer == null) { + return; + } + if (start) { + try { + actionBarLayer.setSubTitleIcon(0, typingDotsDrawable, AndroidUtilities.dp(4)); + typingDotsDrawable.start(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } else { + actionBarLayer.setSubTitleIcon(0, null, 0); + if (typingDotsDrawable != null) { + typingDotsDrawable.stop(); + } + } + } + private void checkAndUpdateAvatar() { TLRPC.FileLocation newPhoto = null; int placeHolderId = 0; @@ -1408,6 +1463,41 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + public boolean openVideoEditor(String videoPath, boolean removeLast, ActionBarLayout parentLayout) { + Bundle args = new Bundle(); + args.putString("videoPath", videoPath); + VideoEditorActivity fragment = new VideoEditorActivity(args); + fragment.setDelegate(new VideoEditorActivity.VideoEditorActivityDelegate() { + @Override + public void didFinishEditVideo(String videoPath, long startTime, long endTime, int resultWidth, int resultHeight, int rotationValue, int originalWidth, int originalHeight, int bitrate, long estimatedSize, long estimatedDuration) { + TLRPC.VideoEditedInfo videoEditedInfo = new TLRPC.VideoEditedInfo(); + videoEditedInfo.startTime = startTime; + videoEditedInfo.endTime = endTime; + videoEditedInfo.rotationValue = rotationValue; + videoEditedInfo.originalWidth = originalWidth; + videoEditedInfo.originalHeight = originalHeight; + videoEditedInfo.bitrate = bitrate; + videoEditedInfo.resultWidth = resultWidth; + videoEditedInfo.resultHeight = resultHeight; + videoEditedInfo.originalPath = videoPath; + processSendingVideo(videoPath, estimatedSize, estimatedDuration, resultWidth, resultHeight, videoEditedInfo); + } + }); + if (parentLayout == null || !parentLayout.presentFragment(fragment, removeLast, true, true)) { + processSendingVideo(videoPath, 0, 0, 0, 0, null); + return false; + } + return true; + } + + private void showAttachmentError() { + if (getParentActivity() == null) { + return; + } + Toast toast = Toast.makeText(getParentActivity(), LocaleController.getString("UnsupportedAttachment", R.string.UnsupportedAttachment), Toast.LENGTH_SHORT); + toast.show(); + } + @Override public void onActivityResultFragment(int requestCode, int resultCode, Intent data) { if (resultCode == Activity.RESULT_OK) { @@ -1458,13 +1548,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (paused) { startVideoEdit = videoPath; } else { - Bundle args = new Bundle(); - args.putString("videoPath", videoPath); - VideoEditorActivity fragment = new VideoEditorActivity(args); - fragment.setDelegate(this); - if (!presentFragment(fragment, false, true)) { - processSendingVideo(videoPath, 0, 0, 0, 0, null); - } + openVideoEditor(videoPath, false, parentLayout); } } else { processSendingVideo(videoPath, 0, 0, 0, 0, null); @@ -1489,29 +1573,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } - @Override - public void didFinishEditVideo(String videoPath, long startTime, long endTime, int resultWidth, int resultHeight, int rotationValue, int originalWidth, int originalHeight, int bitrate, long estimatedSize, long estimatedDuration) { - TLRPC.VideoEditedInfo videoEditedInfo = new TLRPC.VideoEditedInfo(); - videoEditedInfo.startTime = startTime; - videoEditedInfo.endTime = endTime; - videoEditedInfo.rotationValue = rotationValue; - videoEditedInfo.originalWidth = originalWidth; - videoEditedInfo.originalHeight = originalHeight; - videoEditedInfo.bitrate = bitrate; - videoEditedInfo.resultWidth = resultWidth; - videoEditedInfo.resultHeight = resultHeight; - videoEditedInfo.originalPath = videoPath; - processSendingVideo(videoPath, estimatedSize, estimatedDuration, resultWidth, resultHeight, videoEditedInfo); - } - - private void showAttachmentError() { - if (getParentActivity() == null) { - return; - } - Toast toast = Toast.makeText(getParentActivity(), LocaleController.getString("UnsupportedAttachment", R.string.UnsupportedAttachment), Toast.LENGTH_SHORT); - toast.show(); - } - @Override public void saveSelfArgs(Bundle args) { if (currentPicturePath != null) { @@ -1524,6 +1585,20 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not currentPicturePath = args.getString("path"); } + private void removeUnreadPlane(boolean reload) { + if (unreadMessageObject != null) { + messages.remove(unreadMessageObject); + unread_end_reached = true; + first_unread_id = 0; + last_unread_id = 0; + unread_to_load = 0; + unreadMessageObject = null; + if (reload) { + chatAdapter.notifyDataSetChanged(); + } + } + } + public boolean processSendingText(String text) { return chatActivityEnterView.processSendingText(text); } @@ -1855,20 +1930,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not }).start(); } - private void removeUnreadPlane(boolean reload) { - if (unreadMessageObject != null) { - messages.remove(unreadMessageObject); - unread_end_reached = true; - first_unread_id = 0; - last_unread_id = 0; - unread_to_load = 0; - unreadMessageObject = null; - if (reload) { - chatAdapter.notifyDataSetChanged(); - } - } - } - @SuppressWarnings("unchecked") @Override public void didReceivedNotification(int id, final Object... args) { @@ -1948,7 +2009,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not dateMsg.id = 0; MessageObject dateObj = new MessageObject(dateMsg, null); dateObj.type = 10; - dateObj.contentType = 7; + dateObj.contentType = 4; if (forwardLoad) { messages.add(0, dateObj); } else { @@ -2209,7 +2270,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not dateMsg.id = 0; MessageObject dateObj = new MessageObject(dateMsg, null); dateObj.type = 10; - dateObj.contentType = 7; + dateObj.contentType = 4; messages.add(0, dateObj); } if (!obj.isOut() && obj.isUnread()) { @@ -2655,13 +2716,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not AndroidUtilities.RunOnUIThread(new Runnable() { @Override public void run() { - Bundle args = new Bundle(); - args.putString("videoPath", startVideoEdit); - VideoEditorActivity fragment = new VideoEditorActivity(args); - fragment.setDelegate(ChatActivity.this); - if (!presentFragment(fragment, false, true)) { - processSendingVideo(startVideoEdit, 0, 0, 0, 0, null); - } + openVideoEditor(startVideoEdit, false, parentLayout); startVideoEdit = null; } }); @@ -2672,58 +2727,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatListView.setLongClickable(true); } - @Override - public void didSelectPhotos(ArrayList photos) { - processSendingPhotos(photos, null); - } - - @Override - public void didSelectLocation(double latitude, double longitude) { - SendMessagesHelper.getInstance().sendMessage(latitude, longitude, dialog_id); - if (chatListView != null) { - chatListView.setSelectionFromTop(messages.size() - 1, -100000 - chatListView.getPaddingTop()); - } - if (paused) { - scrollToTopOnResume = true; - } - } - - @Override - public void startPhotoSelectActivity() { - try { - Intent photoPickerIntent = new Intent(Intent.ACTION_PICK); - photoPickerIntent.setType("image/*"); - startActivityForResult(photoPickerIntent, 1); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - @Override public void onBeginSlide() { super.onBeginSlide(); chatActivityEnterView.hideEmojiPopup(); } - private void setTypingAnimation(boolean start) { - if (actionBarLayer == null) { - return; - } - if (start) { - try { - actionBarLayer.setSubTitleIcon(0, typingDotsDrawable, AndroidUtilities.dp(4)); - typingDotsDrawable.start(); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } else { - actionBarLayer.setSubTitleIcon(0, null, 0); - if (typingDotsDrawable != null) { - typingDotsDrawable.stop(); - } - } - } - @Override public void onPause() { super.onPause(); @@ -2759,12 +2768,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (view instanceof ChatBaseCell) { ChatBaseCell cell = (ChatBaseCell) view; object = cell.getMessageObject(); - } else { - Object tag = view.getTag(); - if (tag instanceof ChatListRowHolderEx) { - ChatListRowHolderEx holder = (ChatListRowHolderEx) tag; - object = holder.message; - } } if (object != null && object.messageOwner.id < 0 && object.messageOwner.random_id != 0) { visibleMessages.add(object.messageOwner.random_id); @@ -2817,39 +2820,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not fixLayout(false); } - private View getRowParentView(View v) { - if (v instanceof ChatBaseCell) { - return v; - } else { - while (!(v.getTag() instanceof ChatListRowHolderEx)) { - ViewParent parent = v.getParent(); - if (!(parent instanceof View)) { - return null; - } - v = (View)v.getParent(); - if (v == null) { - return null; - } - } - return v; - } - } - public void createMenu(View v, boolean single) { if (actionBarLayer.isActionModeShowed()) { return; } - View parentView = getRowParentView(v); - if (parentView == null) { - return; - } MessageObject message = null; if (v instanceof ChatBaseCell) { message = ((ChatBaseCell)v).getMessageObject(); - } else { - ChatListRowHolderEx holder = (ChatListRowHolderEx)parentView.getTag(); - message = holder.message; + } else if (v instanceof ChatActionCell) { + message = ((ChatActionCell)v).getMessageObject(); } final int type = getMessageType(message); @@ -3094,23 +3074,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not selectedObject = null; } - @Override - public void didSelectFile(DocumentSelectActivity activity, String path) { - activity.finishFragment(); - processSendingDocument(path, path); - } - - @Override - public void startDocumentSelectActivity() { - try { - Intent photoPickerIntent = new Intent(Intent.ACTION_PICK); - photoPickerIntent.setType("*/*"); - startActivityForResult(photoPickerIntent, 21); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - private void forwardSelectedMessages(long did, boolean fromMyName) { if (forwaringMessage != null) { if (!fromMyName) { @@ -3225,25 +3188,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not for (int a = 0; a < count; a++) { View view = chatListView.getChildAt(a); Object tag = view.getTag(); - if (tag instanceof ChatListRowHolderEx) { - ChatListRowHolderEx holder = (ChatListRowHolderEx)tag; - holder.update(); - - boolean disableSelection = false; - boolean selected = false; - if (actionBarLayer.isActionModeShowed()) { - if (selectedMessagesIds.containsKey(holder.message.messageOwner.id)) { - view.setBackgroundColor(0x6633b5e5); - selected = true; - } else { - view.setBackgroundColor(0); - } - disableSelection = true; - } else { - view.setBackgroundColor(0); - } - updateRowBackground(holder, disableSelection, selected); - } else if (view instanceof ChatBaseCell) { + if (view instanceof ChatBaseCell) { ChatBaseCell cell = (ChatBaseCell)view; boolean disableSelection = false; @@ -3267,35 +3212,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } - private void updateRowBackground(ChatListRowHolderEx holder, boolean disableSelection, boolean selected) { - int messageType = holder.message.type; - if (!disableSelection) { - if (messageType == 12) { - holder.chatBubbleView.setBackgroundResource(R.drawable.chat_outgoing_text_states); - holder.chatBubbleView.setPadding(AndroidUtilities.dp(6), AndroidUtilities.dp(6), AndroidUtilities.dp(18), 0); - } else if (messageType == 13) { - holder.chatBubbleView.setBackgroundResource(R.drawable.chat_incoming_text_states); - holder.chatBubbleView.setPadding(AndroidUtilities.dp(15), AndroidUtilities.dp(6), AndroidUtilities.dp(9), 0); - } - } else { - if (messageType == 12) { - if (selected) { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out_selected); - } else { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out); - } - holder.chatBubbleView.setPadding(AndroidUtilities.dp(6), AndroidUtilities.dp(6), AndroidUtilities.dp(18), 0); - } else if (messageType == 13) { - if (selected) { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_in_selected); - } else { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_in); - } - holder.chatBubbleView.setPadding(AndroidUtilities.dp(15), AndroidUtilities.dp(6), AndroidUtilities.dp(9), 0); - } - } - } - private void alertUserOpenError(MessageObject message) { if (getParentActivity() == null) { return; @@ -3329,15 +3245,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not messageToOpen = message; imageReceiver = cell.getPhotoImage(); } - } else if (view.getTag() != null) { - Object tag = view.getTag(); - if (tag instanceof ChatListRowHolderEx) { - ChatListRowHolderEx holder = (ChatListRowHolderEx)tag; - if (holder.message != null && holder.message.messageOwner.id == messageObject.messageOwner.id) { - messageToOpen = holder.message; - imageReceiver = holder.photoImage.imageReceiver; - view = holder.photoImage; - } + } else if (view instanceof ChatActionCell) { + ChatActionCell cell = (ChatActionCell)view; + MessageObject message = cell.getMessageObject(); + if (message != null && message.messageOwner.id == messageObject.messageOwner.id) { + messageToOpen = message; + imageReceiver = cell.getPhotoImage(); } } @@ -3457,26 +3370,156 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not view = new ChatMessageCell(mContext); } if (type == 1) { view = new ChatMediaCell(mContext); - } else if (type == 7) { - view = new ChatActionCell(mContext); - } else if (type == 8) { - LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - view = li.inflate(R.layout.chat_action_change_photo_layout, viewGroup, false); + } else if (type == 2) { + view = new ChatAudioCell(mContext); } else if (type == 3) { - LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - view = li.inflate(R.layout.chat_outgoing_contact_layout, viewGroup, false); - } else if (type == 4) { - LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - if (currentChat != null) { - view = li.inflate(R.layout.chat_group_incoming_contact_layout, viewGroup, false); - } else { - view = li.inflate(R.layout.chat_incoming_contact_layout, viewGroup, false); - } + view = new ChatContactCell(mContext); } else if (type == 6) { LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = li.inflate(R.layout.chat_unread_layout, viewGroup, false); - } else if (type == 2) { - view = new ChatAudioCell(mContext); + } else if (type == 4) { + view = new ChatActionCell(mContext); + } + + if (view instanceof ChatBaseCell) { + ((ChatBaseCell)view).setDelegate(new ChatBaseCell.ChatBaseCellDelegate() { + @Override + public void didPressedUserAvatar(ChatBaseCell cell, TLRPC.User user) { + if (user != null && user.id != UserConfig.getClientUserId()) { + Bundle args = new Bundle(); + args.putInt("user_id", user.id); + presentFragment(new UserProfileActivity(args)); + } + } + + @Override + public void didPressedCancelSendButton(ChatBaseCell cell) { + MessageObject message = cell.getMessageObject(); + if (message.messageOwner.send_state != 0) { + SendMessagesHelper.getInstance().cancelSendingMessage(message); + } + } + + @Override + public void didLongPressed(ChatBaseCell cell) { + createMenu(cell, false); + } + + @Override + public boolean canPerformActions() { + return actionBarLayer != null && !actionBarLayer.isActionModeShowed(); + } + }); + if (view instanceof ChatMediaCell) { + ((ChatMediaCell) view).setMediaDelegate(new ChatMediaCell.ChatMediaCellDelegate() { + @Override + public void didClickedImage(ChatMediaCell cell) { + MessageObject message = cell.getMessageObject(); + if (message.isSendError()) { + createMenu(cell, false); + return; + } else if (message.isSending()) { + return; + } + if (message.type == 1) { + PhotoViewer.getInstance().setParentActivity(getParentActivity()); + PhotoViewer.getInstance().openPhoto(message, ChatActivity.this); + } else if (message.type == 3) { + try { + File f = null; + if (message.messageOwner.attachPath != null && message.messageOwner.attachPath.length() != 0) { + f = new File(message.messageOwner.attachPath); + } + if (f == null || f != null && !f.exists()) { + f = FileLoader.getPathToMessage(message.messageOwner); + } + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setDataAndType(Uri.fromFile(f), "video/mp4"); + getParentActivity().startActivity(intent); + } catch (Exception e) { + alertUserOpenError(message); + } + } else if (message.type == 4) { + if (!isGoogleMapsInstalled()) { + return; + } + LocationActivity fragment = new LocationActivity(); + fragment.setMessageObject(message); + presentFragment(fragment); + } else if (message.type == 9) { + File f = null; + String fileName = message.getFileName(); + if (message.messageOwner.attachPath != null && message.messageOwner.attachPath.length() != 0) { + f = new File(message.messageOwner.attachPath); + } + if (f == null || f != null && !f.exists()) { + f = FileLoader.getPathToMessage(message.messageOwner); + } + if (f != null && f.exists()) { + String realMimeType = null; + try { + Intent intent = new Intent(Intent.ACTION_VIEW); + if (message.type == 8 || message.type == 9) { + MimeTypeMap myMime = MimeTypeMap.getSingleton(); + int idx = fileName.lastIndexOf("."); + if (idx != -1) { + String ext = fileName.substring(idx + 1); + realMimeType = myMime.getMimeTypeFromExtension(ext.toLowerCase()); + if (realMimeType != null) { + intent.setDataAndType(Uri.fromFile(f), realMimeType); + } else { + intent.setDataAndType(Uri.fromFile(f), "text/plain"); + } + } else { + intent.setDataAndType(Uri.fromFile(f), "text/plain"); + } + } + if (realMimeType != null) { + try { + getParentActivity().startActivity(intent); + } catch (Exception e) { + intent.setDataAndType(Uri.fromFile(f), "text/plain"); + getParentActivity().startActivity(intent); + } + } else { + getParentActivity().startActivity(intent); + } + } catch (Exception e) { + alertUserOpenError(message); + } + } + } + } + + @Override + public void didPressedOther(ChatMediaCell cell) { + createMenu(cell, true); + } + }); + } + } else if (view instanceof ChatActionCell) { + ((ChatActionCell)view).setDelegate(new ChatActionCell.ChatActionCellDelegate() { + @Override + public void didClickedImage(ChatActionCell cell) { + MessageObject message = cell.getMessageObject(); + PhotoViewer.getInstance().setParentActivity(getParentActivity()); + PhotoViewer.getInstance().openPhoto(message, ChatActivity.this); + } + + @Override + public void didLongPressed(ChatActionCell cell) { + createMenu(cell, false); + } + + @Override + public void needOpenUserProfile(int uid) { + if (uid != UserConfig.getClientUserId()) { + Bundle args = new Bundle(); + args.putInt("user_id", uid); + presentFragment(new UserProfileActivity(args)); + } + } + }); } } @@ -3495,140 +3538,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (view instanceof ChatBaseCell) { - ((ChatBaseCell)view).delegate = new ChatBaseCell.ChatBaseCellDelegate() { - @Override - public void didPressedUserAvatar(ChatBaseCell cell, TLRPC.User user) { - if (user != null && user.id != UserConfig.getClientUserId()) { - Bundle args = new Bundle(); - args.putInt("user_id", user.id); - presentFragment(new UserProfileActivity(args)); - } - } - - @Override - public void didPressedCancelSendButton(ChatBaseCell cell) { - MessageObject message = cell.getMessageObject(); - if (message.messageOwner.send_state != 0) { - SendMessagesHelper.getInstance().cancelSendingMessage(message); - } - } - - @Override - public void didLongPressed(ChatBaseCell cell) { - createMenu(cell, false); - } - - @Override - public boolean canPerformActions() { - return actionBarLayer != null && !actionBarLayer.isActionModeShowed(); - } - }; - if (view instanceof ChatMediaCell) { - ((ChatMediaCell)view).mediaDelegate = new ChatMediaCell.ChatMediaCellDelegate() { - @Override - public void didClickedImage(ChatMediaCell cell) { - MessageObject message = cell.getMessageObject(); - if (message.isSendError()) { - createMenu(cell, false); - return; - } else if (message.isSending()) { - return; - } - if (message.type == 1) { - PhotoViewer.getInstance().setParentActivity(getParentActivity()); - PhotoViewer.getInstance().openPhoto(message, ChatActivity.this); - } else if (message.type == 3) { - try { - File f = null; - if (message.messageOwner.attachPath != null && message.messageOwner.attachPath.length() != 0) { - f = new File(message.messageOwner.attachPath); - } - if (f == null || f != null && !f.exists()) { - f = FileLoader.getPathToMessage(message.messageOwner); - } - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(Uri.fromFile(f), "video/mp4"); - getParentActivity().startActivity(intent); - } catch (Exception e) { - alertUserOpenError(message); - } - } else if (message.type == 4) { - if (!isGoogleMapsInstalled()) { - return; - } - LocationActivity fragment = new LocationActivity(); - fragment.setMessageObject(message); - presentFragment(fragment); - } else if (message.type == 9) { - File f = null; - String fileName = message.getFileName(); - if (message.messageOwner.attachPath != null && message.messageOwner.attachPath.length() != 0) { - f = new File(message.messageOwner.attachPath); - } - if (f == null || f != null && !f.exists()) { - f = FileLoader.getPathToMessage(message.messageOwner); - } - if (f != null && f.exists()) { - String realMimeType = null; - try { - Intent intent = new Intent(Intent.ACTION_VIEW); - if (message.type == 8 || message.type == 9) { - MimeTypeMap myMime = MimeTypeMap.getSingleton(); - int idx = fileName.lastIndexOf("."); - if (idx != -1) { - String ext = fileName.substring(idx + 1); - realMimeType = myMime.getMimeTypeFromExtension(ext.toLowerCase()); - if (realMimeType != null) { - intent.setDataAndType(Uri.fromFile(f), realMimeType); - } else { - intent.setDataAndType(Uri.fromFile(f), "text/plain"); - } - } else { - intent.setDataAndType(Uri.fromFile(f), "text/plain"); - } - } - if (realMimeType != null) { - try { - getParentActivity().startActivity(intent); - } catch (Exception e) { - intent.setDataAndType(Uri.fromFile(f), "text/plain"); - getParentActivity().startActivity(intent); - } - } else { - getParentActivity().startActivity(intent); - } - } catch (Exception e) { - alertUserOpenError(message); - } - } - } - } - - @Override - public void didPressedOther(ChatMediaCell cell) { - createMenu(cell, true); - } - }; - } - - ((ChatBaseCell)view).isChat = currentChat != null; - ((ChatBaseCell)view).setMessageObject(message); - ((ChatBaseCell)view).setCheckPressed(!disableSelection, disableSelection && selected); + ChatBaseCell baseCell = (ChatBaseCell)view; + baseCell.isChat = currentChat != null; + baseCell.setMessageObject(message); + baseCell.setCheckPressed(!disableSelection, disableSelection && selected); if (view instanceof ChatAudioCell && MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_AUDIO)) { ((ChatAudioCell)view).downloadAudioIfNeed(); } } else if (view instanceof ChatActionCell) { - ((ChatActionCell)view).setMessageObject(message); - ((ChatActionCell)view).setUseBlackBackground(isCustomTheme); - } else { - ChatListRowHolderEx holder = (ChatListRowHolderEx)view.getTag(); - if (holder == null) { - holder = new ChatListRowHolderEx(view, message.type); - view.setTag(holder); - } - holder.message = message; - updateRowBackground(holder, disableSelection, selected); - holder.update(); + ChatActionCell actionCell = (ChatActionCell)view; + actionCell.setMessageObject(message); + actionCell.setUseBlackBackground(isCustomTheme); + } + if (type == 6) { + TextView messageTextView = (TextView)view.findViewById(R.id.chat_message_text); + messageTextView.setText(LocaleController.formatPluralString("NewMessages", unread_to_load)); } return view; @@ -3652,7 +3576,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public int getViewTypeCount() { - return 9; + return 7; } @Override @@ -3669,318 +3593,4 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return count == 0; } } - - public class ChatListRowHolderEx { - public BackupImageView avatarImageView; - public TextView nameTextView; - public TextView messageTextView; - public MessageActionLayout messageLayoutAction; - public TextView timeTextView; - public BackupImageView photoImage; - public ImageView halfCheckImage; - public ImageView checkImage; - public MessageObject message; - public TextView phoneTextView; - public BackupImageView contactAvatar; - public View contactView; - public ImageView addContactButton; - public View addContactView; - public View chatBubbleView; - - public void update() { - TLRPC.User fromUser = MessagesController.getInstance().getUser(message.messageOwner.from_id); - - int type = message.type; - - if (timeTextView != null) { - timeTextView.setText(LocaleController.formatterDay.format((long) (message.messageOwner.date) * 1000)); - } - - if (avatarImageView != null && fromUser != null) { - TLRPC.FileLocation photo = null; - if (fromUser.photo != null) { - photo = fromUser.photo.photo_small; - } - int placeHolderId = AndroidUtilities.getUserAvatarForId(fromUser.id); - avatarImageView.setImage(photo, "50_50", placeHolderId); - } - - if (type != 12 && type != 13 && nameTextView != null && fromUser != null && type != 8 && type != 9) { - nameTextView.setText(ContactsController.formatName(fromUser.first_name, fromUser.last_name)); - nameTextView.setTextColor(AndroidUtilities.getColorForId(message.messageOwner.from_id)); - } - - if (type == 11 || type == 10) { - int width = 0; - if (AndroidUtilities.isTablet()) { - width = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(30); - } else { - width = AndroidUtilities.displaySize.x - AndroidUtilities.dp(30); - } - messageTextView.setText(message.messageText); - messageTextView.setMaxWidth(width); - - if (type == 11) { - if (message.messageOwner.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) { - photoImage.setImage(message.messageOwner.action.newUserPhoto.photo_small, "50_50", AndroidUtilities.getUserAvatarForId(currentUser.id)); - } else { - PhotoObject photo = PhotoObject.getClosestImageWithSize(message.photoThumbs, AndroidUtilities.dp(64)); - if (photo != null) { - if (photo.image != null) { - photoImage.setImageBitmap(photo.image); - } else { - photoImage.setImage(photo.photoOwner.location, "50_50", AndroidUtilities.getGroupAvatarForId(currentChat.id)); - } - } else { - photoImage.setImageResource(AndroidUtilities.getGroupAvatarForId(currentChat.id)); - } - } - photoImage.imageReceiver.setVisible(!PhotoViewer.getInstance().isShowingImage(message), false); - } - } else if (type == 12 || type == 13) { - TLRPC.User contactUser = MessagesController.getInstance().getUser(message.messageOwner.media.user_id); - if (contactUser != null) { - nameTextView.setText(ContactsController.formatName(message.messageOwner.media.first_name, message.messageOwner.media.last_name)); - nameTextView.setTextColor(AndroidUtilities.getColorForId(contactUser.id)); - String phone = message.messageOwner.media.phone_number; - if (phone != null && phone.length() != 0) { - if (!phone.startsWith("+")) { - phone = "+" + phone; - } - phoneTextView.setText(PhoneFormat.getInstance().format(phone)); - } else { - phoneTextView.setText("Unknown"); - } - TLRPC.FileLocation photo = null; - if (contactUser.photo != null) { - photo = contactUser.photo.photo_small; - } - int placeHolderId = AndroidUtilities.getUserAvatarForId(contactUser.id); - contactAvatar.setImage(photo, "50_50", placeHolderId); - if (contactUser.id != UserConfig.getClientUserId() && ContactsController.getInstance().contactsDict.get(contactUser.id) == null) { - addContactView.setVisibility(View.VISIBLE); - } else { - addContactView.setVisibility(View.GONE); - } - } else { - nameTextView.setText(ContactsController.formatName(message.messageOwner.media.first_name, message.messageOwner.media.last_name)); - nameTextView.setTextColor(AndroidUtilities.getColorForId(message.messageOwner.media.user_id)); - String phone = message.messageOwner.media.phone_number; - if (phone != null && phone.length() != 0) { - if (message.messageOwner.media.user_id != 0 && !phone.startsWith("+")) { - phone = "+" + phone; - } - phoneTextView.setText(PhoneFormat.getInstance().format(phone)); - } else { - phoneTextView.setText("Unknown"); - } - contactAvatar.setImageResource(AndroidUtilities.getUserAvatarForId(message.messageOwner.media.user_id)); - addContactView.setVisibility(View.GONE); - } - } else if (type == 6) { - messageTextView.setTextSize(16); - messageTextView.setText(LocaleController.formatPluralString("NewMessages", unread_to_load)); - } - - if (message.isFromMe()) { - if (halfCheckImage != null) { - if (message.isSending()) { - checkImage.setVisibility(View.INVISIBLE); - halfCheckImage.setImageResource(R.drawable.msg_clock); - halfCheckImage.setVisibility(View.VISIBLE); - } else if (message.isSendError()) { - halfCheckImage.setVisibility(View.VISIBLE); - halfCheckImage.setImageResource(R.drawable.msg_warning); - if (checkImage != null) { - checkImage.setVisibility(View.INVISIBLE); - } - } else if (message.isSent()) { - if (!message.isUnread()) { - halfCheckImage.setVisibility(View.VISIBLE); - checkImage.setVisibility(View.VISIBLE); - halfCheckImage.setImageResource(R.drawable.msg_halfcheck); - } else { - halfCheckImage.setVisibility(View.VISIBLE); - checkImage.setVisibility(View.INVISIBLE); - halfCheckImage.setImageResource(R.drawable.msg_check); - } - } - } - } - } - - public ChatListRowHolderEx(View view, int type) { - avatarImageView = (BackupImageView)view.findViewById(R.id.chat_group_avatar_image); - nameTextView = (TextView)view.findViewById(R.id.chat_user_group_name); - messageLayoutAction = (MessageActionLayout)view.findViewById(R.id.message_action_layout); - timeTextView = (TextView)view.findViewById(R.id.chat_time_text); - photoImage = (BackupImageView)view.findViewById(R.id.chat_photo_image); - halfCheckImage = (ImageView)view.findViewById(R.id.chat_row_halfcheck); - checkImage = (ImageView)view.findViewById(R.id.chat_row_check); - messageTextView = (TextView)view.findViewById(R.id.chat_message_text); - phoneTextView = (TextView)view.findViewById(R.id.phone_text_view); - contactAvatar = (BackupImageView)view.findViewById(R.id.contact_avatar); - contactView = view.findViewById(R.id.shared_layout); - addContactButton = (ImageView)view.findViewById(R.id.add_contact_button); - addContactView = view.findViewById(R.id.add_contact_view); - chatBubbleView = view.findViewById(R.id.chat_bubble_layout); - if (messageTextView != null) { - messageTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, MessagesController.getInstance().fontSize); - } - - if (messageLayoutAction != null) { - if (isCustomTheme) { - messageLayoutAction.setBackgroundResource(R.drawable.system_black); - } else { - messageLayoutAction.setBackgroundResource(R.drawable.system_blue); - } - } - - if (addContactButton != null) { - addContactButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (actionBarLayer.isActionModeShowed()) { - processRowSelect(view); - return; - } - Bundle args = new Bundle(); - args.putInt("user_id", message.messageOwner.media.user_id); - args.putString("phone", message.messageOwner.media.phone_number); - presentFragment(new ContactAddActivity(args)); - } - }); - - addContactButton.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - createMenu(v, false); - return true; - } - }); - } - - if (contactView != null) { - contactView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (message.type == 12 || message.type == 13) { - if (actionBarLayer.isActionModeShowed()) { - processRowSelect(view); - return; - } - if (message.messageOwner.media.user_id != UserConfig.getClientUserId()) { - TLRPC.User user = null; - if (message.messageOwner.media.user_id != 0) { - user = MessagesController.getInstance().getUser(message.messageOwner.media.user_id); - } - if (user != null) { - Bundle args = new Bundle(); - args.putInt("user_id", message.messageOwner.media.user_id); - presentFragment(new UserProfileActivity(args)); - } else { - if (message.messageOwner.media.phone_number == null || message.messageOwner.media.phone_number.length() == 0) { - return; - } - if (getParentActivity() == null) { - return; - } - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setItems(new CharSequence[] {LocaleController.getString("Copy", R.string.Copy), LocaleController.getString("Call", R.string.Call)}, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (i == 1) { - try { - Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + message.messageOwner.media.phone_number)); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - getParentActivity().startActivity(intent); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } else if (i == 0) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { - android.text.ClipboardManager clipboard = (android.text.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); - clipboard.setText(message.messageOwner.media.phone_number); - } else { - android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); - android.content.ClipData clip = android.content.ClipData.newPlainText("label", message.messageOwner.media.phone_number); - clipboard.setPrimaryClip(clip); - } - } - } - } - ); - showAlertDialog(builder); - } - } - } - } - }); - - contactView.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - createMenu(v, false); - return true; - } - }); - } - - if (contactAvatar != null) { - contactAvatar.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - - } - }); - } - - if (avatarImageView != null) { - avatarImageView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (actionBarLayer.isActionModeShowed()) { - processRowSelect(view); - return; - } - if (message != null) { - Bundle args = new Bundle(); - args.putInt("user_id", message.messageOwner.from_id); - presentFragment(new UserProfileActivity(args)); - } - } - }); - } - - if (photoImage != null) { - photoImage.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - processOnClick(view); - } - }); - - photoImage.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - createMenu(v, false); - return true; - } - }); - } - } - - private void processOnClick(View view) { - if (actionBarLayer.isActionModeShowed()) { - processRowSelect(view); - return; - } - if (message != null) { - if (message.type == 11) { - PhotoViewer.getInstance().setParentActivity(getParentActivity()); - PhotoViewer.getInstance().openPhoto(message, ChatActivity.this); - } - } - } - } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index c1470125..11817f09 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -661,12 +661,11 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa actionBarLayout.presentFragment(fragment, false, true, true); } - Bundle args2 = new Bundle(); - args2.putString("videoPath", videoPath); - VideoEditorActivity fragment2 = new VideoEditorActivity(args2); - fragment2.setDelegate(fragment); - presentFragment(fragment2, true, true); - if (!AndroidUtilities.isTablet()) { + if (!fragment.openVideoEditor(videoPath, true, actionBarLayout)) { + if (!AndroidUtilities.isTablet()) { + actionBarLayout.presentFragment(fragment, true); + } + } else if (!AndroidUtilities.isTablet()) { actionBarLayout.addFragmentToStack(fragment, actionBarLayout.fragmentsStack.size() - 1); } } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/HorizontalListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/HorizontalListView.java index 59fef1a8..0bef5eb8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/HorizontalListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/HorizontalListView.java @@ -207,7 +207,7 @@ public class HorizontalListView extends AdapterView { v = list.poll(); } View child = mAdapter.getView(mRightViewIndex, v, this); - child.setTag(1, type); + child.setTag(type); addAndMeasureChild(child, -1); rightEdge += child.getMeasuredWidth(); @@ -234,7 +234,7 @@ public class HorizontalListView extends AdapterView { v = list.poll(); } View child = mAdapter.getView(mLeftViewIndex, v, this); - child.setTag(1, type); + child.setTag(type); addAndMeasureChild(child, 0); leftEdge -= child.getMeasuredWidth(); @@ -248,7 +248,7 @@ public class HorizontalListView extends AdapterView { while (child != null && child.getRight() + dx <= 0) { mDisplayOffset += child.getMeasuredWidth(); - int type = (Integer) child.getTag(1); + int type = (Integer) child.getTag(); LinkedList list = mRemovedViewQueue.get(type); if (list == null) { list = new LinkedList(); @@ -263,7 +263,7 @@ public class HorizontalListView extends AdapterView { child = getChildAt(getChildCount() - 1); while (child != null && child.getLeft() + dx >= getWidth()) { - int type = (Integer) child.getTag(1); + int type = (Integer) child.getTag(); LinkedList list = mRemovedViewQueue.get(type); if (list == null) { list = new LinkedList(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/MessageActionLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/MessageActionLayout.java deleted file mode 100644 index 793b45f7..00000000 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/MessageActionLayout.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * This is the source code of Telegram for Android v. 1.3.2. - * It is licensed under GNU GPL v. 2 or later. - * You should have received a copy of the license in this archive (see LICENSE). - * - * Copyright Nikolai Kudashov, 2013. - */ - -package org.telegram.ui.Views; - -import android.widget.FrameLayout; - -import org.telegram.android.AndroidUtilities; -import org.telegram.messenger.R; - -public class MessageActionLayout extends FrameLayout { - public TightTextView messageTextView; - - public MessageActionLayout(android.content.Context context) { - super(context); - } - - public MessageActionLayout(android.content.Context context, android.util.AttributeSet attrs) { - super(context, attrs); - } - - public MessageActionLayout(android.content.Context context, android.util.AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - setMeasuredDimension(messageTextView.linesMaxWidth + AndroidUtilities.dp(14), getMeasuredHeight()); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - messageTextView = (TightTextView)findViewById(R.id.chat_message_text); - } -} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/TightTextView.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/TightTextView.java deleted file mode 100644 index 2aa782a3..00000000 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/TightTextView.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * This is the source code of Telegram for Android v. 1.3.2. - * It is licensed under GNU GPL v. 2 or later. - * You should have received a copy of the license in this archive (see LICENSE). - * - * Copyright Nikolai Kudashov, 2013. - */ - -package org.telegram.ui.Views; - -import android.content.Context; -import android.text.Layout; -import android.util.AttributeSet; -import android.widget.TextView; - -import org.telegram.messenger.FileLog; - -public class TightTextView extends TextView { - private boolean hasMaxWidth; - public int maxWidth; - - public int lastLineWidth = 0; - public int linesMaxWidth = 0; - public int lines = 0; - - public TightTextView(Context context) { - this(context, null, 0); - } - - public TightTextView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public TightTextView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - try { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - int measuredWidth = getMeasuredWidth(); - Layout layout = getLayout(); - lines = layout.getLineCount(); - float lastLeft = layout.getLineLeft(lines - 1); - float lastLine = layout.getLineWidth(lines - 1); - int lastLineWidthWithLeft; - int linesMaxWidthWithLeft; - boolean hasNonRTL = false; - linesMaxWidth = lastLineWidth = (int)Math.ceil(lastLine); - linesMaxWidthWithLeft = lastLineWidthWithLeft = (int)Math.ceil(lastLine + lastLeft); - if (lastLeft == 0) { - hasNonRTL = true; - } - if (hasMaxWidth) { - int specModeW = MeasureSpec.getMode(widthMeasureSpec); - if (specModeW != MeasureSpec.EXACTLY) { - if (lines > 1) { - float textRealMaxWidth = 0, textRealMaxWidthWithLeft = 0; - for (int n = 0; n < lines; ++n) { - float lineWidth; - float lineLeft; - try { - lineWidth = layout.getLineWidth(n); - lineLeft = layout.getLineLeft(n); - } catch (Exception e) { - FileLog.e("tmessages", e); - return; - } - - if (lineLeft == 0) { - hasNonRTL = true; - } - textRealMaxWidth = Math.max(textRealMaxWidth, lineWidth); - textRealMaxWidthWithLeft = Math.max(textRealMaxWidthWithLeft, lineWidth + lineLeft); - linesMaxWidth = Math.max(linesMaxWidth, (int)Math.ceil(lineWidth)); - linesMaxWidthWithLeft = Math.max(linesMaxWidthWithLeft, (int)Math.ceil(lineWidth + lineLeft)); - } - if (hasNonRTL) { - textRealMaxWidth = textRealMaxWidthWithLeft; - lastLineWidth = lastLineWidthWithLeft; - linesMaxWidth = linesMaxWidthWithLeft; - } else { - lastLineWidth = linesMaxWidth; - } - int w = (int)Math.ceil(textRealMaxWidth); - if (w < getMeasuredWidth()) { - super.onMeasure(MeasureSpec.makeMeasureSpec(w, MeasureSpec.AT_MOST), heightMeasureSpec); - } - } else { - super.onMeasure(MeasureSpec.makeMeasureSpec(Math.min(maxWidth, linesMaxWidth), MeasureSpec.AT_MOST), heightMeasureSpec); - } - } - } - } catch (Exception e) { - FileLog.e("tmessages", e); - try { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } catch (Exception e2) { - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)); - FileLog.e("tmessages", e2); - } - } - } - - @Override - public void setMaxWidth(int maxpixels) { - super.setMaxWidth(maxpixels); - hasMaxWidth = true; - maxWidth = maxpixels; - } - - @Override - public void setMaxEms(int maxems) { - super.setMaxEms(maxems); - hasMaxWidth = true; - } -} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/URLSpanNoUnderline.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/URLSpanNoUnderline.java new file mode 100644 index 00000000..c2d7b1e0 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/URLSpanNoUnderline.java @@ -0,0 +1,24 @@ +/* + * This is the source code of Telegram for Android v. 1.7.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2014. + */ + +package org.telegram.ui.Views; + +import android.text.TextPaint; +import android.text.style.URLSpan; + +public class URLSpanNoUnderline extends URLSpan { + public URLSpanNoUnderline(String url) { + super(url); + } + + @Override + public void updateDrawState(TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(false); + } +} diff --git a/TMessagesProj/src/main/res/layout/chat_action_change_photo_layout.xml b/TMessagesProj/src/main/res/layout/chat_action_change_photo_layout.xml deleted file mode 100644 index 73b62564..00000000 --- a/TMessagesProj/src/main/res/layout/chat_action_change_photo_layout.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/layout/chat_action_message_layout.xml b/TMessagesProj/src/main/res/layout/chat_action_message_layout.xml deleted file mode 100644 index 1229042c..00000000 --- a/TMessagesProj/src/main/res/layout/chat_action_message_layout.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - \ No newline at end of file From 5bbfba2092139b41bdd80ba4bf7e89961cff7bd7 Mon Sep 17 00:00:00 2001 From: DrKLO Date: Fri, 17 Oct 2014 00:02:44 +0400 Subject: [PATCH 08/18] UI improvements --- TMessagesProj/build.gradle | 2 +- .../telegram/android/MessagesController.java | 16 +- .../org/telegram/android/MessagesStorage.java | 67 ++- .../telegram/android/SendMessagesHelper.java | 353 ++++++++++++- .../java/org/telegram/messenger/TLRPC.java | 2 + .../org/telegram/ui/Cells/ChatAudioCell.java | 33 +- .../org/telegram/ui/Cells/ChatBaseCell.java | 2 +- .../telegram/ui/Cells/ChatContactCell.java | 491 +++++++++--------- .../org/telegram/ui/Cells/ChatMediaCell.java | 6 +- .../java/org/telegram/ui/ChatActivity.java | 408 +++------------ .../java/org/telegram/ui/LaunchActivity.java | 8 +- .../org/telegram/ui/SettingsActivity.java | 2 +- .../ui/SettingsBlockedUsersActivity.java | 2 +- .../org/telegram/ui/UserProfileActivity.java | 2 +- .../chat_group_incoming_contact_layout.xml | 95 ---- .../layout/chat_incoming_contact_layout.xml | 87 ---- .../layout/chat_outgoing_contact_layout.xml | 117 ----- .../src/main/res/values-ar/strings.xml | 1 + .../src/main/res/values-de/strings.xml | 1 + .../src/main/res/values-es/strings.xml | 1 + .../src/main/res/values-it/strings.xml | 1 + .../src/main/res/values-ko/strings.xml | 1 + .../src/main/res/values-nl/strings.xml | 1 + .../src/main/res/values-pt-rBR/strings.xml | 1 + .../src/main/res/values-pt-rPT/strings.xml | 1 + TMessagesProj/src/main/res/values/strings.xml | 1 + 26 files changed, 777 insertions(+), 925 deletions(-) delete mode 100644 TMessagesProj/src/main/res/layout/chat_group_incoming_contact_layout.xml delete mode 100644 TMessagesProj/src/main/res/layout/chat_incoming_contact_layout.xml delete mode 100644 TMessagesProj/src/main/res/layout/chat_outgoing_contact_layout.xml diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index 7f216ab8..235ad19b 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -80,7 +80,7 @@ android { defaultConfig { minSdkVersion 8 targetSdkVersion 19 - versionCode 357 + versionCode 358 versionName "1.9.5" } } diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java index f11d4fc5..b4e1a6f4 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java @@ -3551,7 +3551,15 @@ public class MessagesController implements NotificationCenter.NotificationCenter } if (object instanceof TLRPC.TL_decryptedMessageLayer) { - object = ((TLRPC.TL_decryptedMessageLayer) object).message; + final TLRPC.TL_decryptedMessageLayer layer = (TLRPC.TL_decryptedMessageLayer)object; + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + chat.seq_in = layer.out_seq_no; + MessagesStorage.getInstance().updateEncryptedChatSeq(chat); + } + }); + object = layer.message; } if (object instanceof TLRPC.TL_decryptedMessage) { @@ -3890,6 +3898,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter salt[a] = (byte) ((byte) (Utilities.random.nextDouble() * 256) ^ res.random[a]); } encryptedChat.a_or_b = salt; + encryptedChat.seq_in = 1; + encryptedChat.seq_out = 0; BigInteger p = new BigInteger(1, MessagesStorage.secretPBytes); BigInteger g_b = BigInteger.valueOf(MessagesStorage.secretG); g_b = g_b.modPow(new BigInteger(1, salt), p); @@ -4033,8 +4043,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter } TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat) response; chat.user_id = chat.participant_id; - putEncryptedChat(chat, false); + chat.seq_in = 0; + chat.seq_out = 1; chat.a_or_b = salt; + putEncryptedChat(chat, false); TLRPC.TL_dialog dialog = new TLRPC.TL_dialog(); dialog.id = ((long) chat.id) << 32; dialog.unread_count = 0; diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java index abbec523..09dffff1 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java @@ -93,7 +93,7 @@ public class MessagesStorage { database.executeFast("CREATE TABLE users(uid INTEGER PRIMARY KEY, name TEXT, status INTEGER, data BLOB)").stepThis().dispose(); database.executeFast("CREATE TABLE messages(mid INTEGER PRIMARY KEY, uid INTEGER, read_state INTEGER, send_state INTEGER, date INTEGER, data BLOB, out INTEGER, ttl INTEGER, media INTEGER)").stepThis().dispose(); database.executeFast("CREATE TABLE chats(uid INTEGER PRIMARY KEY, name TEXT, data BLOB)").stepThis().dispose(); - database.executeFast("CREATE TABLE enc_chats(uid INTEGER PRIMARY KEY, user INTEGER, name TEXT, data BLOB, g BLOB, authkey BLOB, ttl INTEGER, layer INTEGER)").stepThis().dispose(); + database.executeFast("CREATE TABLE enc_chats(uid INTEGER PRIMARY KEY, user INTEGER, name TEXT, data BLOB, g BLOB, authkey BLOB, ttl INTEGER, layer INTEGER, seq_in INTEGER, seq_out INTEGER)").stepThis().dispose(); database.executeFast("CREATE TABLE dialogs(did INTEGER PRIMARY KEY, date INTEGER, unread_count INTEGER, last_mid INTEGER)").stepThis().dispose(); database.executeFast("CREATE TABLE chat_settings(uid INTEGER PRIMARY KEY, participants BLOB)").stepThis().dispose(); database.executeFast("CREATE TABLE contacts(uid INTEGER PRIMARY KEY, mutual INTEGER)").stepThis().dispose(); @@ -291,6 +291,8 @@ public class MessagesStorage { } if (version == 6 && version < 7) { database.executeFast("ALTER TABLE enc_chats ADD COLUMN layer INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE enc_chats ADD COLUMN seq_in INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE enc_chats ADD COLUMN seq_out INTEGER default 0").stepThis().dispose(); database.executeFast("PRAGMA user_version = 7").stepThis().dispose(); version = 7; } @@ -491,7 +493,7 @@ public class MessagesStorage { if (!encryptedChatIds.isEmpty()) { String stringToLoad = TextUtils.join(",", encryptedChatIds); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer FROM enc_chats WHERE uid IN(%s)", stringToLoad)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer, seq_in, seq_out FROM enc_chats WHERE uid IN(%s)", stringToLoad)); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { @@ -505,6 +507,8 @@ public class MessagesStorage { chat.auth_key = cursor.byteArrayValue(3); chat.ttl = cursor.intValue(4); chat.layer = cursor.intValue(5); + chat.seq_in = cursor.intValue(6); + chat.seq_out = cursor.intValue(7); } buffersStorage.reuseFreeBuffer(data); } @@ -1232,7 +1236,7 @@ public class MessagesStorage { cursor.dispose(); if (needEncrypted) { - cursor = database.queryFinalized("SELECT q.data, u.name, q.user, q.g, q.authkey, q.ttl, u.data, u.status, q.layer FROM enc_chats as q INNER JOIN dialogs as d ON (q.uid << 32) = d.did INNER JOIN users as u ON q.user = u.uid"); + cursor = database.queryFinalized("SELECT q.data, u.name, q.user, q.g, q.authkey, q.ttl, u.data, u.status, q.layer, q.seq_in, q.seq_out FROM enc_chats as q INNER JOIN dialogs as d ON (q.uid << 32) = d.did INNER JOIN users as u ON q.user = u.uid"); while (cursor.next()) { String name = cursor.stringValue(1); if (name.startsWith(q) || name.contains(" " + q)) { @@ -1245,6 +1249,8 @@ public class MessagesStorage { chat.auth_key = cursor.byteArrayValue(4); chat.ttl = cursor.intValue(5); chat.layer = cursor.intValue(8); + chat.seq_in = cursor.intValue(9); + chat.seq_out = cursor.intValue(10); TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data2, data2.readInt32()); if (user.status != null) { @@ -1720,7 +1726,7 @@ public class MessagesStorage { if (!encryptedChatIds.isEmpty()) { String stringToLoad = TextUtils.join(",", encryptedChatIds); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer FROM enc_chats WHERE uid IN(%s)", stringToLoad)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer, seq_in, seq_out FROM enc_chats WHERE uid IN(%s)", stringToLoad)); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { @@ -1734,6 +1740,8 @@ public class MessagesStorage { chat.auth_key = cursor.byteArrayValue(3); chat.ttl = cursor.intValue(4); chat.layer = cursor.intValue(5); + chat.seq_in = cursor.intValue(6); + chat.seq_out = cursor.intValue(7); } buffersStorage.reuseFreeBuffer(data); } @@ -2126,6 +2134,31 @@ public class MessagesStorage { }); } + public void updateEncryptedChatSeq(final TLRPC.EncryptedChat chat) { + if (chat == null) { + return; + } + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + SQLitePreparedStatement state = null; + try { + state = database.executeFast("UPDATE enc_chats SET seq_in = ?, seq_out = ? WHERE uid = ?"); + state.bindInteger(1, chat.seq_in); + state.bindInteger(2, chat.seq_out); + state.bindInteger(3, chat.id); + state.step(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (state != null) { + state.dispose(); + } + } + } + }); + } + public void updateEncryptedChatTTL(final TLRPC.EncryptedChat chat) { if (chat == null) { return; @@ -2183,7 +2216,7 @@ public class MessagesStorage { public void run() { SQLitePreparedStatement state = null; try { - state = database.executeFast("UPDATE enc_chats SET data = ?, g = ?, authkey = ?, ttl = ?, layer = ? WHERE uid = ?"); + state = database.executeFast("UPDATE enc_chats SET data = ?, g = ?, authkey = ?, ttl = ?, layer = ?, seq_in = ?, seq_out = ? WHERE uid = ?"); ByteBufferDesc data = buffersStorage.getFreeBuffer(chat.getObjectSize()); ByteBufferDesc data2 = buffersStorage.getFreeBuffer(chat.a_or_b != null ? chat.a_or_b.length : 1); ByteBufferDesc data3 = buffersStorage.getFreeBuffer(chat.auth_key != null ? chat.auth_key.length : 1); @@ -2199,7 +2232,9 @@ public class MessagesStorage { state.bindByteBuffer(3, data3.buffer); state.bindInteger(4, chat.ttl); state.bindInteger(5, chat.layer); - state.bindInteger(6, chat.id); + state.bindInteger(6, chat.seq_in); + state.bindInteger(7, chat.seq_out); + state.bindInteger(8, chat.id); state.step(); buffersStorage.reuseFreeBuffer(data); buffersStorage.reuseFreeBuffer(data2); @@ -2224,7 +2259,7 @@ public class MessagesStorage { public void run() { try { int userToLoad = 0; - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer FROM enc_chats WHERE uid = %d", chat_id)); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer, seq_in, seq_out FROM enc_chats WHERE uid = %d", chat_id)); if (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { @@ -2236,6 +2271,8 @@ public class MessagesStorage { chat.auth_key = cursor.byteArrayValue(3); chat.ttl = cursor.intValue(4); chat.layer = cursor.intValue(5); + chat.seq_in = cursor.intValue(6); + chat.seq_out = cursor.intValue(7); } buffersStorage.reuseFreeBuffer(data); } @@ -2276,7 +2313,7 @@ public class MessagesStorage { @Override public void run() { try { - SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_chats VALUES(?, ?, ?, ?, ?, ?, ?, ?)"); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_chats VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); ByteBufferDesc data = buffersStorage.getFreeBuffer(chat.getObjectSize()); ByteBufferDesc data2 = buffersStorage.getFreeBuffer(chat.a_or_b != null ? chat.a_or_b.length : 1); ByteBufferDesc data3 = buffersStorage.getFreeBuffer(chat.auth_key != null ? chat.auth_key.length : 1); @@ -2301,6 +2338,8 @@ public class MessagesStorage { state.bindByteBuffer(6, data3.buffer); state.bindInteger(7, chat.ttl); state.bindInteger(8, chat.layer); + state.bindInteger(9, chat.seq_in); + state.bindInteger(10, chat.seq_out); state.step(); state.dispose(); buffersStorage.reuseFreeBuffer(data); @@ -3160,7 +3199,7 @@ public class MessagesStorage { if (!encryptedToLoad.isEmpty()) { String toLoad = TextUtils.join(",", encryptedToLoad); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer FROM enc_chats WHERE uid IN(%s)", toLoad)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer, seq_in, seq_out FROM enc_chats WHERE uid IN(%s)", toLoad)); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { @@ -3174,6 +3213,8 @@ public class MessagesStorage { chat.auth_key = cursor.byteArrayValue(3); chat.ttl = cursor.intValue(4); chat.layer = cursor.intValue(5); + chat.seq_in = cursor.intValue(6); + chat.seq_out = cursor.intValue(7); } buffersStorage.reuseFreeBuffer(data); } @@ -3417,7 +3458,7 @@ public class MessagesStorage { if (!encryptedToLoad.isEmpty()) { String toLoad = TextUtils.join(",", encryptedToLoad); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer FROM enc_chats WHERE uid IN(%s)", toLoad)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer, seq_in, seq_out FROM enc_chats WHERE uid IN(%s)", toLoad)); while (cursor.next()) { try { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); @@ -3433,6 +3474,8 @@ public class MessagesStorage { chat.auth_key = cursor.byteArrayValue(3); chat.ttl = cursor.intValue(4); chat.layer = cursor.intValue(5); + chat.seq_in = cursor.intValue(6); + chat.seq_out = cursor.intValue(7); } } buffersStorage.reuseFreeBuffer(data); @@ -3706,7 +3749,7 @@ public class MessagesStorage { public TLRPC.EncryptedChat getEncryptedChat(final int chat_id) { TLRPC.EncryptedChat chat = null; try { - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer FROM enc_chats WHERE uid = %d", chat_id)); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer, seq_in, seq_out FROM enc_chats WHERE uid = %d", chat_id)); if (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { @@ -3717,6 +3760,8 @@ public class MessagesStorage { chat.auth_key = cursor.byteArrayValue(3); chat.ttl = cursor.intValue(4); chat.layer = cursor.intValue(5); + chat.seq_in = cursor.intValue(6); + chat.seq_out = cursor.intValue(7); } } buffersStorage.reuseFreeBuffer(data); diff --git a/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java index b98618c5..d37614a0 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java @@ -9,7 +9,13 @@ package org.telegram.android; import android.graphics.Bitmap; +import android.media.MediaMetadataRetriever; +import android.media.MediaPlayer; +import android.media.ThumbnailUtils; import android.net.Uri; +import android.os.Build; +import android.provider.MediaStore; +import android.webkit.MimeTypeMap; import org.telegram.messenger.BuffersStorage; import org.telegram.messenger.ByteBufferDesc; @@ -22,6 +28,7 @@ import org.telegram.messenger.TLObject; import org.telegram.messenger.TLRPC; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; +import org.telegram.ui.ApplicationLoader; import java.io.File; import java.util.ArrayList; @@ -616,10 +623,16 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter performSendMessageRequest(reqSend, newMsgObj, null); } } else { - TLRPC.TL_decryptedMessage_old reqSend = new TLRPC.TL_decryptedMessage_old(); + TLRPC.TL_decryptedMessage reqSend; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessage(); + reqSend.ttl = encryptedChat.ttl; + } else { + reqSend = new TLRPC.TL_decryptedMessage_old(); + reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))]; + Utilities.random.nextBytes(reqSend.random_bytes); + } reqSend.random_id = newMsg.random_id; - reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))]; - Utilities.random.nextBytes(reqSend.random_bytes); reqSend.message = message; reqSend.media = new TLRPC.TL_decryptedMessageMediaEmpty(); performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null, null, null); @@ -768,10 +781,16 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } } } else { - TLRPC.TL_decryptedMessage_old reqSend = new TLRPC.TL_decryptedMessage_old(); + TLRPC.TL_decryptedMessage reqSend; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessage(); + reqSend.ttl = encryptedChat.ttl; + } else { + reqSend = new TLRPC.TL_decryptedMessage_old(); + reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))]; + Utilities.random.nextBytes(reqSend.random_bytes); + } reqSend.random_id = newMsg.random_id; - reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))]; - Utilities.random.nextBytes(reqSend.random_bytes); reqSend.message = ""; if (type == 1) { reqSend.media = new TLRPC.TL_decryptedMessageMediaGeoPoint(); @@ -1124,12 +1143,15 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 17) { TLRPC.TL_decryptedMessageLayer layer = new TLRPC.TL_decryptedMessageLayer(); layer.layer = CURRENT_SECRET_CHAT_LAYER; - layer.in_seq_no = 0; //TODO - layer.out_seq_no = 0; + layer.in_seq_no = chat.seq_in; + layer.out_seq_no = chat.seq_out; layer.message = req; layer.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))]; Utilities.random.nextBytes(layer.random_bytes); toEncryptObject = layer; + + chat.seq_out += 2; + MessagesStorage.getInstance().updateEncryptedChatSeq(chat); } else { toEncryptObject = req; } @@ -1715,4 +1737,319 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter return photo; } } + + private static void prepareSendingDocumentInternal(final String path, String originalPath, final long dialog_id) { + if (path == null || path.length() == 0) { + return; + } + final File f = new File(path); + if (!f.exists() || f.length() == 0) { + return; + } + + boolean isEncrypted = (int)dialog_id == 0; + + String name = f.getName(); + if (name == null) { + name = "noname"; + } + String ext = ""; + int idx = path.lastIndexOf("."); + if (idx != -1) { + ext = path.substring(idx + 1); + } + if (originalPath != null) { + originalPath += "" + f.length(); + } + + TLRPC.TL_document document = (TLRPC.TL_document)MessagesStorage.getInstance().getSentFile(originalPath, !isEncrypted ? 1 : 4); + if (document == null && !path.equals(originalPath)) { + document = (TLRPC.TL_document)MessagesStorage.getInstance().getSentFile(path + f.length(), !isEncrypted ? 1 : 4); + } + if (document == null) { + document = new TLRPC.TL_document(); + document.id = 0; + document.user_id = UserConfig.getClientUserId(); + document.date = ConnectionsManager.getInstance().getCurrentTime(); + document.file_name = name; + document.size = (int)f.length(); + document.dc_id = 0; + if (ext.length() != 0) { + MimeTypeMap myMime = MimeTypeMap.getSingleton(); + String mimeType = myMime.getMimeTypeFromExtension(ext.toLowerCase()); + if (mimeType != null) { + document.mime_type = mimeType; + } else { + document.mime_type = "application/octet-stream"; + } + } else { + document.mime_type = "application/octet-stream"; + } + if (document.mime_type.equals("image/gif")) { + try { + Bitmap bitmap = ImageLoader.loadBitmap(f.getAbsolutePath(), null, 90, 90); + if (bitmap != null) { + document.thumb = ImageLoader.scaleAndSaveImage(bitmap, 90, 90, 55, isEncrypted); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + if (document.thumb == null) { + document.thumb = new TLRPC.TL_photoSizeEmpty(); + document.thumb.type = "s"; + } + } + + final TLRPC.TL_document documentFinal = document; + final String originalPathFinal = originalPath; + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + SendMessagesHelper.getInstance().sendMessage(documentFinal, originalPathFinal, path, dialog_id); + } + }); + } + + public static void prepareSendingDocument(String path, String originalPath, long dialog_id) { + if (path == null || originalPath == null) { + return; + } + ArrayList paths = new ArrayList(); + ArrayList originalPaths = new ArrayList(); + paths.add(path); + originalPaths.add(originalPath); + prepareSendingDocuments(paths, originalPaths, dialog_id); + } + + public static void prepareSendingDocuments(final ArrayList paths, final ArrayList originalPaths, final long dialog_id) { + if (paths == null && originalPaths == null || paths != null && originalPaths != null && paths.size() != originalPaths.size()) { + return; + } + new Thread(new Runnable() { + @Override + public void run() { + for (int a = 0; a < paths.size(); a++) { + prepareSendingDocumentInternal(paths.get(a), originalPaths.get(a), dialog_id); + } + } + }).start(); + } + + public static void prepareSendingPhoto(String imageFilePath, Uri imageUri, long dialog_id) { + ArrayList paths = null; + ArrayList uris = null; + if (imageFilePath != null && imageFilePath.length() != 0) { + paths = new ArrayList(); + paths.add(imageFilePath); + } + if (imageUri != null) { + uris = new ArrayList(); + uris.add(imageUri); + } + prepareSendingPhotos(paths, uris, dialog_id); + } + + public static void prepareSendingPhotos(ArrayList paths, ArrayList uris, final long dialog_id) { + if (paths == null && uris == null || paths != null && paths.isEmpty() || uris != null && uris.isEmpty()) { + return; + } + final ArrayList pathsCopy = new ArrayList(); + final ArrayList urisCopy = new ArrayList(); + if (paths != null) { + pathsCopy.addAll(paths); + } + if (uris != null) { + urisCopy.addAll(uris); + } + new Thread(new Runnable() { + @Override + public void run() { + boolean isEncrypted = (int)dialog_id == 0; + + ArrayList sendAsDocuments = null; + ArrayList sendAsDocumentsOriginal = null; + int count = !pathsCopy.isEmpty() ? pathsCopy.size() : urisCopy.size(); + String path = null; + Uri uri = null; + for (int a = 0; a < count; a++) { + if (!pathsCopy.isEmpty()) { + path = pathsCopy.get(a); + } else if (!urisCopy.isEmpty()) { + uri = urisCopy.get(a); + } + + String originalPath = path; + String tempPath = path; + if (tempPath == null && uri != null) { + tempPath = Utilities.getPath(uri); + originalPath = uri.toString(); + } + + boolean isGif = false; + if (tempPath != null && tempPath.endsWith(".gif")) { + isGif = true; + } else if (tempPath == null && uri != null) { + isGif = MediaController.isGif(uri); + if (isGif) { + originalPath = uri.toString(); + tempPath = MediaController.copyDocumentToCache(uri, "gif"); + } + } + + if (isGif) { + if (sendAsDocuments == null) { + sendAsDocuments = new ArrayList(); + sendAsDocumentsOriginal = new ArrayList(); + } + sendAsDocuments.add(tempPath); + sendAsDocumentsOriginal.add(originalPath); + } else { + if (tempPath != null) { + File temp = new File(tempPath); + originalPath += temp.length() + "_" + temp.lastModified(); + } else { + originalPath = null; + } + TLRPC.TL_photo photo = (TLRPC.TL_photo)MessagesStorage.getInstance().getSentFile(originalPath, !isEncrypted ? 0 : 3); + if (photo == null && uri != null) { + photo = (TLRPC.TL_photo)MessagesStorage.getInstance().getSentFile(Utilities.getPath(uri), !isEncrypted ? 0 : 3); + } + if (photo == null) { + photo = SendMessagesHelper.getInstance().generatePhotoSizes(path, uri); + } + if (photo != null) { + final String originalPathFinal = originalPath; + final TLRPC.TL_photo photoFinal = photo; + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + SendMessagesHelper.getInstance().sendMessage(photoFinal, originalPathFinal, dialog_id); + } + }); + } + } + } + if (sendAsDocuments != null && !sendAsDocuments.isEmpty()) { + for (int a = 0; a < sendAsDocuments.size(); a++) { + prepareSendingDocumentInternal(sendAsDocuments.get(a), sendAsDocumentsOriginal.get(a), dialog_id); + } + } + } + }).start(); + } + + public static void prepareSendingVideo(final String videoPath, final long estimatedSize, final long duration, final int width, final int height, final TLRPC.VideoEditedInfo videoEditedInfo, final long dialog_id) { + if (videoPath == null || videoPath.length() == 0) { + return; + } + new Thread(new Runnable() { + @Override + public void run() { + boolean isEncrypted = (int)dialog_id == 0; + + String path = videoPath; + String originalPath = videoPath; + File temp = new File(originalPath); + originalPath += temp.length() + "_" + temp.lastModified(); + if (videoEditedInfo != null) { + originalPath += duration + "_" + videoEditedInfo.startTime + "_" + videoEditedInfo.endTime; + } + TLRPC.TL_video video = (TLRPC.TL_video)MessagesStorage.getInstance().getSentFile(originalPath, !isEncrypted ? 2 : 5); + if (video == null) { + Bitmap thumb = ThumbnailUtils.createVideoThumbnail(videoPath, MediaStore.Video.Thumbnails.MINI_KIND); + TLRPC.PhotoSize size = ImageLoader.scaleAndSaveImage(thumb, 90, 90, 55, isEncrypted); + video = new TLRPC.TL_video(); + video.thumb = size; + if (video.thumb == null) { + video.thumb = new TLRPC.TL_photoSizeEmpty(); + video.thumb.type = "s"; + } else { + video.thumb.type = "s"; + } + video.caption = ""; + video.mime_type = "video/mp4"; + video.id = 0; + UserConfig.saveConfig(false); + + if (videoEditedInfo != null) { + video.duration = (int)(duration / 1000); + if (videoEditedInfo.rotationValue == 90 || videoEditedInfo.rotationValue == 270) { + video.w = height; + video.h = width; + } else { + video.w = width; + video.h = height; + } + video.size = (int)estimatedSize; + video.videoEditedInfo = videoEditedInfo; + String fileName = Integer.MIN_VALUE + "_" + UserConfig.lastLocalId + ".mp4"; + UserConfig.lastLocalId--; + File cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName); + UserConfig.saveConfig(false); + path = cacheFile.getAbsolutePath(); + } else { + if (temp != null && temp.exists()) { + video.size = (int) temp.length(); + } + boolean infoObtained = false; + if (Build.VERSION.SDK_INT >= 14) { + MediaMetadataRetriever mediaMetadataRetriever = null; + try { + mediaMetadataRetriever = new MediaMetadataRetriever(); + mediaMetadataRetriever.setDataSource(videoPath); + String width = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH); + if (width != null) { + video.w = Integer.parseInt(width); + } + String height = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT); + if (height != null) { + video.h = Integer.parseInt(height); + } + String duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); + if (duration != null) { + video.duration = (int) Math.ceil(Long.parseLong(duration) / 1000.0f); + } + infoObtained = true; + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + try { + if (mediaMetadataRetriever != null) { + mediaMetadataRetriever.release(); + mediaMetadataRetriever = null; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + if (!infoObtained) { + try { + MediaPlayer mp = MediaPlayer.create(ApplicationLoader.applicationContext, Uri.fromFile(new File(videoPath))); + if (mp != null) { + video.duration = (int) Math.ceil(mp.getDuration() / 1000.0f); + video.w = mp.getVideoWidth(); + video.h = mp.getVideoHeight(); + mp.release(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + } + + final TLRPC.TL_video videoFinal = video; + final String originalPathFinal = originalPath; + final String finalPath = path; + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + SendMessagesHelper.getInstance().sendMessage(videoFinal, originalPathFinal, finalPath, dialog_id); + } + }); + } + }).start(); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java index 1de7d7df..f985df2c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java @@ -9330,6 +9330,8 @@ public class TLRPC { public int user_id; public int ttl; public int layer; + public int seq_in; + public int seq_out; } public static class FileLocation extends TLObject { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java index febf6890..b6041c68 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java @@ -44,9 +44,9 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega private int buttonState = 0; private int buttonX; private int buttonY; - private int buttonPressed = 0; + private boolean buttonPressed = false; - private int avatarPressed = 0; + private boolean avatarPressed = false; private StaticLayout timeLayout; private int timeX; @@ -56,7 +56,6 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega public TLRPC.User audioUser; private TLRPC.FileLocation currentPhoto; - private String currentNameString; public ChatAudioCell(Context context) { super(context); @@ -115,40 +114,40 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega int side = AndroidUtilities.dp(36); if (event.getAction() == MotionEvent.ACTION_DOWN) { if (x >= buttonX && x <= buttonX + side && y >= buttonY && y <= buttonY + side) { - buttonPressed = 1; + buttonPressed = true; invalidate(); result = true; } else if (avatarImage.isInsideImage(x, y)) { - avatarPressed = 1; + avatarPressed = true; result = true; } - } else if (buttonPressed == 1) { + } else if (buttonPressed) { if (event.getAction() == MotionEvent.ACTION_UP) { - buttonPressed = 0; + buttonPressed = false; playSoundEffect(SoundEffectConstants.CLICK); didPressedButton(); invalidate(); } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { - buttonPressed = 0; + buttonPressed = false; invalidate(); } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (!(x >= buttonX && x <= buttonX + side && y >= buttonY && y <= buttonY + side)) { - buttonPressed = 0; + buttonPressed = false; invalidate(); } } - } else if (avatarPressed == 1) { + } else if (avatarPressed) { if (event.getAction() == MotionEvent.ACTION_UP) { - avatarPressed = 0; + avatarPressed = false; playSoundEffect(SoundEffectConstants.CLICK); if (delegate != null) { delegate.didPressedUserAvatar(this, audioUser); } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { - avatarPressed = 0; + avatarPressed = false; } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (!avatarImage.isInsideImage(x, y)) { - avatarPressed = 0; + avatarPressed = false; } } } @@ -301,7 +300,7 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega int x; if (currentMessageObject.isOut()) { - x = layoutWidth - backgroundWidth + AndroidUtilities.dp(9); + x = layoutWidth - backgroundWidth + AndroidUtilities.dp(8); seekBarX = layoutWidth - backgroundWidth + AndroidUtilities.dp(97); buttonX = layoutWidth - backgroundWidth + AndroidUtilities.dp(67); timeX = layoutWidth - backgroundWidth + AndroidUtilities.dp(71); @@ -356,7 +355,7 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega } avatarImage.setImage(currentPhoto, "50_50", getResources().getDrawable(AndroidUtilities.getUserAvatarForId(uid)), false); } else { - avatarImage.setImage((TLRPC.FileLocation)null, "50_50", getResources().getDrawable(AndroidUtilities.getUserAvatarForId(uid)), false); + avatarImage.setImage(null, "50_50", getResources().getDrawable(AndroidUtilities.getUserAvatarForId(uid)), false); } if (messageObject.isOut()) { @@ -380,7 +379,7 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega return; } - avatarImage.draw(canvas, avatarImage.getImageX(), avatarImage.getImageY(), AndroidUtilities.dp(50), AndroidUtilities.dp(50)); + avatarImage.draw(canvas, avatarImage.getImageX(), avatarImage.getImageY(), avatarImage.getImageHeight(), avatarImage.getImageHeight()); canvas.save(); if (buttonState == 0 || buttonState == 1) { @@ -399,7 +398,7 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega } else { timePaint.setColor(0xff70b15c); } - Drawable buttonDrawable = statesDrawable[state][buttonPressed]; + Drawable buttonDrawable = statesDrawable[state][buttonPressed ? 1 : 0]; int side = AndroidUtilities.dp(36); int x = (side - buttonDrawable.getIntrinsicWidth()) / 2; int y = (side - buttonDrawable.getIntrinsicHeight()) / 2; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java index e3e55f58..ebc90b2c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java @@ -94,7 +94,7 @@ public class ChatBaseCell extends BaseCell { private StaticLayout timeLayout; protected int timeWidth; - protected int timeX; + private int timeX; private TextPaint currentTimePaint; private String currentTimeString; protected boolean drawTime = true; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java index 19d7da81..7b0f14d2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java @@ -9,263 +9,280 @@ package org.telegram.ui.Cells; import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.TextUtils; +import android.view.MotionEvent; +import android.view.SoundEffectConstants; + +import org.telegram.PhoneFormat.PhoneFormat; +import org.telegram.android.AndroidUtilities; +import org.telegram.android.ContactsController; +import org.telegram.android.ImageReceiver; +import org.telegram.android.LocaleController; +import org.telegram.android.MessageObject; +import org.telegram.android.MessagesController; +import org.telegram.messenger.R; +import org.telegram.messenger.TLRPC; +import org.telegram.messenger.UserConfig; public class ChatContactCell extends ChatBaseCell { + public static interface ChatContactCellDelegate { + public abstract void didClickAddButton(ChatContactCell cell, TLRPC.User user); + public abstract void didClickPhone(ChatContactCell cell); + } + + private static TextPaint namePaint; + private static TextPaint phonePaint; + private static Drawable addContactDrawable; + private static Paint linePaint; + + private ImageReceiver avatarImage; + + private StaticLayout nameLayout; + private StaticLayout phoneLayout; + + private TLRPC.User contactUser; + private TLRPC.FileLocation currentPhoto; + + private boolean avatarPressed = false; + private boolean buttonPressed = false; + private boolean drawAddButton = false; + private int namesWidth = 0; + + private ChatContactCellDelegate contactDelegate = null; + public ChatContactCell(Context context) { super(context); + if (namePaint == null) { + namePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); + namePaint.setTextSize(AndroidUtilities.dp(15)); + + phonePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); + phonePaint.setTextSize(AndroidUtilities.dp(15)); + phonePaint.setColor(0xff000000); + + addContactDrawable = getResources().getDrawable(R.drawable.ic_ab_add_member); + + linePaint = new Paint(); + linePaint.setStrokeWidth(AndroidUtilities.dp(1)); + } + avatarImage = new ImageReceiver(this); } - /* - public class ChatListRowHolderEx { - public BackupImageView avatarImageView; - public TextView nameTextView; - public TextView messageTextView; - public TextView timeTextView; - public ImageView halfCheckImage; - public ImageView checkImage; - public MessageObject message; - public TextView phoneTextView; - public BackupImageView contactAvatar; - public View contactView; - public ImageView addContactButton; - public View addContactView; - public View chatBubbleView; + public void setContactDelegate(ChatContactCellDelegate delegate) { + this.contactDelegate = delegate; + } - public void update() { - TLRPC.User fromUser = MessagesController.getInstance().getUser(message.messageOwner.from_id); + @Override + protected boolean isUserDataChanged() { + if (currentMessageObject == null) { + return false; + } - int type = message.type; + contactUser = MessagesController.getInstance().getUser(currentMessageObject.messageOwner.media.user_id); - if (timeTextView != null) { - timeTextView.setText(LocaleController.formatterDay.format((long) (message.messageOwner.date) * 1000)); + TLRPC.FileLocation newPhoto = null; + if (contactUser != null && contactUser.photo != null) { + newPhoto = contactUser.photo.photo_small; + } + + return currentPhoto == null && newPhoto != null || currentPhoto != null && newPhoto == null || currentPhoto != null && newPhoto != null && (currentPhoto.local_id != newPhoto.local_id || currentPhoto.volume_id != newPhoto.volume_id) || super.isUserDataChanged(); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + float x = event.getX(); + float y = event.getY(); + + boolean result = false; + int side = AndroidUtilities.dp(36); + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (x >= avatarImage.getImageX() && x <= avatarImage.getImageX() + namesWidth && y >= avatarImage.getImageY() && y <= avatarImage.getImageY() + avatarImage.getImageHeight()) { + avatarPressed = true; + result = true; + } else if (x >= avatarImage.getImageX() - AndroidUtilities.dp(44) && y >= AndroidUtilities.dp(20) && x <= avatarImage.getImageX() - AndroidUtilities.dp(10) && y <= AndroidUtilities.dp(52)) { + buttonPressed = true; + result = true; } - - if (avatarImageView != null && fromUser != null) { - TLRPC.FileLocation photo = null; - if (fromUser.photo != null) { - photo = fromUser.photo.photo_small; + if (result) { + startCheckLongPress(); + } + } else { + if (event.getAction() != MotionEvent.ACTION_MOVE) { + cancelCheckLongPress(); + } + if (avatarPressed) { + if (event.getAction() == MotionEvent.ACTION_UP) { + avatarPressed = false; + playSoundEffect(SoundEffectConstants.CLICK); + if (contactUser != null) { + if (delegate != null) { + delegate.didPressedUserAvatar(this, contactUser); + } + } else { + if (contactDelegate != null) { + contactDelegate.didClickPhone(this); + } + } + } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { + avatarPressed = false; + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + if (!avatarImage.isInsideImage(x, y)) { + avatarPressed = false; + } } - int placeHolderId = AndroidUtilities.getUserAvatarForId(fromUser.id); - avatarImageView.setImage(photo, "50_50", placeHolderId); - } - - if (type != 12 && type != 13 && nameTextView != null && fromUser != null && type != 8 && type != 9) { - nameTextView.setText(ContactsController.formatName(fromUser.first_name, fromUser.last_name)); - nameTextView.setTextColor(AndroidUtilities.getColorForId(message.messageOwner.from_id)); - } - - if (type == 12 || type == 13) { - TLRPC.User contactUser = MessagesController.getInstance().getUser(message.messageOwner.media.user_id); - if (contactUser != null) { - nameTextView.setText(ContactsController.formatName(message.messageOwner.media.first_name, message.messageOwner.media.last_name)); - nameTextView.setTextColor(AndroidUtilities.getColorForId(contactUser.id)); - String phone = message.messageOwner.media.phone_number; - if (phone != null && phone.length() != 0) { - if (!phone.startsWith("+")) { - phone = "+" + phone; - } - phoneTextView.setText(PhoneFormat.getInstance().format(phone)); - } else { - phoneTextView.setText("Unknown"); + } else if (buttonPressed) { + if (event.getAction() == MotionEvent.ACTION_UP) { + buttonPressed = false; + playSoundEffect(SoundEffectConstants.CLICK); + if (contactUser != null && contactDelegate != null) { + contactDelegate.didClickAddButton(this, contactUser); } - TLRPC.FileLocation photo = null; - if (contactUser.photo != null) { - photo = contactUser.photo.photo_small; - } - int placeHolderId = AndroidUtilities.getUserAvatarForId(contactUser.id); - contactAvatar.setImage(photo, "50_50", placeHolderId); - if (contactUser.id != UserConfig.getClientUserId() && ContactsController.getInstance().contactsDict.get(contactUser.id) == null) { - addContactView.setVisibility(View.VISIBLE); - } else { - addContactView.setVisibility(View.GONE); - } - } else { - nameTextView.setText(ContactsController.formatName(message.messageOwner.media.first_name, message.messageOwner.media.last_name)); - nameTextView.setTextColor(AndroidUtilities.getColorForId(message.messageOwner.media.user_id)); - String phone = message.messageOwner.media.phone_number; - if (phone != null && phone.length() != 0) { - if (message.messageOwner.media.user_id != 0 && !phone.startsWith("+")) { - phone = "+" + phone; - } - phoneTextView.setText(PhoneFormat.getInstance().format(phone)); - } else { - phoneTextView.setText("Unknown"); - } - contactAvatar.setImageResource(AndroidUtilities.getUserAvatarForId(message.messageOwner.media.user_id)); - addContactView.setVisibility(View.GONE); - } - } else if (type == 6) { - messageTextView.setTextSize(16); - messageTextView.setText(LocaleController.formatPluralString("NewMessages", unread_to_load)); - } - - if (message.isFromMe()) { - if (halfCheckImage != null) { - if (message.isSending()) { - checkImage.setVisibility(View.INVISIBLE); - halfCheckImage.setImageResource(R.drawable.msg_clock); - halfCheckImage.setVisibility(View.VISIBLE); - } else if (message.isSendError()) { - halfCheckImage.setVisibility(View.VISIBLE); - halfCheckImage.setImageResource(R.drawable.msg_warning); - if (checkImage != null) { - checkImage.setVisibility(View.INVISIBLE); - } - } else if (message.isSent()) { - if (!message.isUnread()) { - halfCheckImage.setVisibility(View.VISIBLE); - checkImage.setVisibility(View.VISIBLE); - halfCheckImage.setImageResource(R.drawable.msg_halfcheck); - } else { - halfCheckImage.setVisibility(View.VISIBLE); - checkImage.setVisibility(View.INVISIBLE); - halfCheckImage.setImageResource(R.drawable.msg_check); - } + } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { + buttonPressed = false; + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + if (!(x >= avatarImage.getImageX() - AndroidUtilities.dp(44) && y >= AndroidUtilities.dp(20) && x <= avatarImage.getImageX() - AndroidUtilities.dp(10) && y <= AndroidUtilities.dp(52))) { + buttonPressed = false; } } } } - - public ChatListRowHolderEx(View view, int type) { - avatarImageView = (BackupImageView)view.findViewById(R.id.chat_group_avatar_image); - nameTextView = (TextView)view.findViewById(R.id.chat_user_group_name); - timeTextView = (TextView)view.findViewById(R.id.chat_time_text); - halfCheckImage = (ImageView)view.findViewById(R.id.chat_row_halfcheck); - checkImage = (ImageView)view.findViewById(R.id.chat_row_check); - messageTextView = (TextView)view.findViewById(R.id.chat_message_text); - phoneTextView = (TextView)view.findViewById(R.id.phone_text_view); - contactAvatar = (BackupImageView)view.findViewById(R.id.contact_avatar); - contactView = view.findViewById(R.id.shared_layout); - addContactButton = (ImageView)view.findViewById(R.id.add_contact_button); - addContactView = view.findViewById(R.id.add_contact_view); - chatBubbleView = view.findViewById(R.id.chat_bubble_layout); - if (messageTextView != null) { - messageTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, MessagesController.getInstance().fontSize); - } - - if (addContactButton != null) { - addContactButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (actionBarLayer.isActionModeShowed()) { - processRowSelect(view); - return; - } - Bundle args = new Bundle(); - args.putInt("user_id", message.messageOwner.media.user_id); - args.putString("phone", message.messageOwner.media.phone_number); - presentFragment(new ContactAddActivity(args)); - } - }); - - addContactButton.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - createMenu(v, false); - return true; - } - }); - } - - if (contactView != null) { - contactView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (message.type == 12 || message.type == 13) { - if (actionBarLayer.isActionModeShowed()) { - processRowSelect(view); - return; - } - if (message.messageOwner.media.user_id != UserConfig.getClientUserId()) { - TLRPC.User user = null; - if (message.messageOwner.media.user_id != 0) { - user = MessagesController.getInstance().getUser(message.messageOwner.media.user_id); - } - if (user != null) { - Bundle args = new Bundle(); - args.putInt("user_id", message.messageOwner.media.user_id); - presentFragment(new UserProfileActivity(args)); - } else { - if (message.messageOwner.media.phone_number == null || message.messageOwner.media.phone_number.length() == 0) { - return; - } - if (getParentActivity() == null) { - return; - } - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setItems(new CharSequence[] {LocaleController.getString("Copy", R.string.Copy), LocaleController.getString("Call", R.string.Call)}, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (i == 1) { - try { - Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + message.messageOwner.media.phone_number)); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - getParentActivity().startActivity(intent); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } else if (i == 0) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { - android.text.ClipboardManager clipboard = (android.text.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); - clipboard.setText(message.messageOwner.media.phone_number); - } else { - android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); - android.content.ClipData clip = android.content.ClipData.newPlainText("label", message.messageOwner.media.phone_number); - clipboard.setPrimaryClip(clip); - } - } - } - } - ); - showAlertDialog(builder); - } - } - } - } - }); - - contactView.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - createMenu(v, false); - return true; - } - }); - } - - if (contactAvatar != null) { - contactAvatar.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - - } - }); - } - - if (avatarImageView != null) { - avatarImageView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (actionBarLayer.isActionModeShowed()) { - processRowSelect(view); - return; - } - if (message != null) { - Bundle args = new Bundle(); - args.putInt("user_id", message.messageOwner.from_id); - presentFragment(new UserProfileActivity(args)); - } - } - }); - } + if (!result) { + result = super.onTouchEvent(event); } - private void processOnClick(View view) { - if (actionBarLayer.isActionModeShowed()) { - processRowSelect(view); + return result; + } + + @Override + public void setMessageObject(MessageObject messageObject) { + if (currentMessageObject != messageObject || isUserDataChanged()) { + + int uid = messageObject.messageOwner.media.user_id; + contactUser = MessagesController.getInstance().getUser(uid); + + drawAddButton = contactUser != null && uid != UserConfig.getClientUserId() && ContactsController.getInstance().contactsDict.get(uid) == null; + + int maxWidth; + if (AndroidUtilities.isTablet()) { + maxWidth = (int) (AndroidUtilities.getMinTabletSide() * 0.7f); + } else { + maxWidth = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.7f); } + maxWidth -= AndroidUtilities.dp(58 + (drawAddButton ? 52 : 0)); + + if (contactUser != null) { + if (contactUser.photo != null) { + currentPhoto = contactUser.photo.photo_small; + } + avatarImage.setImage(currentPhoto, "50_50", getResources().getDrawable(AndroidUtilities.getUserAvatarForId(uid)), false); + } else { + avatarImage.setImage(null, "50_50", getResources().getDrawable(AndroidUtilities.getUserAvatarForId(uid)), false); + } + + String currentNameString = ContactsController.formatName(messageObject.messageOwner.media.first_name, messageObject.messageOwner.media.last_name); + int nameWidth = Math.min((int) Math.ceil(namePaint.measureText(currentNameString)), maxWidth); + + CharSequence stringFinal = TextUtils.ellipsize(currentNameString.replace("\n", " "), namePaint, nameWidth, TextUtils.TruncateAt.END); + nameLayout = new StaticLayout(stringFinal, namePaint, nameWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + if (nameLayout.getLineCount() > 0) { + nameWidth = (int)Math.ceil(nameLayout.getLineWidth(0)); + } else { + nameWidth = 0; + } + + String phone = messageObject.messageOwner.media.phone_number; + if (phone != null && phone.length() != 0) { + if (!phone.startsWith("+")) { + phone = "+" + phone; + } + phone = PhoneFormat.getInstance().format(phone); + } else { + phone = LocaleController.getString("Unknown", R.string.Unknown); + } + int phoneWidth = Math.min((int) Math.ceil(phonePaint.measureText(phone)), maxWidth); + stringFinal = TextUtils.ellipsize(phone.replace("\n", " "), phonePaint, phoneWidth, TextUtils.TruncateAt.END); + phoneLayout = new StaticLayout(stringFinal, phonePaint, phoneWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + if (phoneLayout.getLineCount() > 0) { + phoneWidth = (int)Math.ceil(phoneLayout.getLineWidth(0)); + } else { + phoneWidth = 0; + } + + namesWidth = Math.max(nameWidth, phoneWidth); + backgroundWidth = AndroidUtilities.dp(75 + (drawAddButton ? 52 : 0)) + namesWidth; + + super.setMessageObject(messageObject); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), AndroidUtilities.dp(71)); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + + if (currentMessageObject == null) { + return; + } + + int x; + + if (currentMessageObject.isOut()) { + x = layoutWidth - backgroundWidth + AndroidUtilities.dp(6); + } else { + if (isChat) { + x = AndroidUtilities.dp(67); + } else { + x = AndroidUtilities.dp(14); + } + } + avatarImage.setImageCoords(x + (drawAddButton ? AndroidUtilities.dp(52) : 0), AndroidUtilities.dp(7), AndroidUtilities.dp(42), AndroidUtilities.dp(42)); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (currentMessageObject == null) { + return; + } + + avatarImage.draw(canvas, avatarImage.getImageX(), avatarImage.getImageY(), avatarImage.getImageWidth(), avatarImage.getImageWidth()); + + if (nameLayout != null) { + canvas.save(); + canvas.translate(avatarImage.getImageX() + avatarImage.getImageWidth() + AndroidUtilities.dp(9), AndroidUtilities.dp(8)); + namePaint.setColor(AndroidUtilities.getColorForId(currentMessageObject.messageOwner.media.user_id)); + nameLayout.draw(canvas); + canvas.restore(); + } + if (phoneLayout != null) { + canvas.save(); + canvas.translate(avatarImage.getImageX() + avatarImage.getImageWidth() + AndroidUtilities.dp(9), AndroidUtilities.dp(29)); + phoneLayout.draw(canvas); + canvas.restore(); + } + + if (drawAddButton) { + if (currentMessageObject.isOut()) { + linePaint.setColor(0x9670b15c); + } else { + linePaint.setColor(0xffe8e8e8); + } + canvas.drawLine(avatarImage.getImageX() - AndroidUtilities.dp(4), avatarImage.getImageY(), avatarImage.getImageX() - AndroidUtilities.dp(4), AndroidUtilities.dp(62), linePaint); + + setDrawableBounds(addContactDrawable, avatarImage.getImageX() - AndroidUtilities.dp(44), AndroidUtilities.dp(20)); + addContactDrawable.draw(canvas); } } - */ } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java index f7310955..8952b629 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java @@ -569,7 +569,11 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD } if (currentMessageObject.isSecretMedia()) { - w = h = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.5f); + if (AndroidUtilities.isTablet()) { + w = h = (int) (AndroidUtilities.getMinTabletSide() * 0.5f); + } else { + w = h = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.5f); + } } photoWidth = w; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 2096f86d..ac0fd5fc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -20,12 +20,8 @@ import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; -import android.graphics.Bitmap; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.media.MediaMetadataRetriever; -import android.media.MediaPlayer; -import android.media.ThumbnailUtils; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -51,7 +47,6 @@ import android.widget.Toast; import org.telegram.android.AndroidUtilities; import org.telegram.PhoneFormat.PhoneFormat; -import org.telegram.android.ImageLoader; import org.telegram.android.LocaleController; import org.telegram.android.MediaController; import org.telegram.android.MessagesStorage; @@ -470,7 +465,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not fragment.setDelegate(new PhotoPickerActivity.PhotoPickerActivityDelegate() { @Override public void didSelectPhotos(ArrayList photos) { - processSendingPhotos(photos, null); + SendMessagesHelper.prepareSendingPhotos(photos, null, dialog_id); } @Override @@ -531,7 +526,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void didSelectFile(DocumentSelectActivity activity, String path) { activity.finishFragment(); - processSendingDocument(path, path); + SendMessagesHelper.prepareSendingDocument(path, path, dialog_id); } @Override @@ -1480,11 +1475,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not videoEditedInfo.resultWidth = resultWidth; videoEditedInfo.resultHeight = resultHeight; videoEditedInfo.originalPath = videoPath; - processSendingVideo(videoPath, estimatedSize, estimatedDuration, resultWidth, resultHeight, videoEditedInfo); + SendMessagesHelper.prepareSendingVideo(videoPath, estimatedSize, estimatedDuration, resultWidth, resultHeight, videoEditedInfo, dialog_id); } }); if (parentLayout == null || !parentLayout.presentFragment(fragment, removeLast, true, true)) { - processSendingVideo(videoPath, 0, 0, 0, 0, null); + SendMessagesHelper.prepareSendingVideo(videoPath, 0, 0, 0, 0, null, dialog_id); return false; } return true; @@ -1503,14 +1498,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (resultCode == Activity.RESULT_OK) { if (requestCode == 0) { Utilities.addMediaToGallery(currentPicturePath); - processSendingPhoto(currentPicturePath, null); + SendMessagesHelper.prepareSendingPhoto(currentPicturePath, null, dialog_id); currentPicturePath = null; } else if (requestCode == 1) { if (data == null || data.getData() == null) { showAttachmentError(); return; } - processSendingPhoto(null, data.getData()); + SendMessagesHelper.prepareSendingPhoto(null, data.getData(), dialog_id); } else if (requestCode == 2) { String videoPath = null; if (data != null) { @@ -1551,7 +1546,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not openVideoEditor(videoPath, false, parentLayout); } } else { - processSendingVideo(videoPath, 0, 0, 0, 0, null); + SendMessagesHelper.prepareSendingVideo(videoPath, 0, 0, 0, 0, null, dialog_id); } } else if (requestCode == 21) { if (data == null || data.getData() == null) { @@ -1568,7 +1563,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not showAttachmentError(); return; } - processSendingDocument(tempPath, originalPath); + SendMessagesHelper.prepareSendingDocument(tempPath, originalPath, dialog_id); } } } @@ -1603,333 +1598,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return chatActivityEnterView.processSendingText(text); } - public void processSendingPhoto(String imageFilePath, Uri imageUri) { - ArrayList paths = null; - ArrayList uris = null; - if (imageFilePath != null && imageFilePath.length() != 0) { - paths = new ArrayList(); - paths.add(imageFilePath); - } - if (imageUri != null) { - uris = new ArrayList(); - uris.add(imageUri); - } - processSendingPhotos(paths, uris); - } - - public void processSendingPhotos(ArrayList paths, ArrayList uris) { - if (paths == null && uris == null || paths != null && paths.isEmpty() || uris != null && uris.isEmpty()) { - return; - } - final ArrayList pathsCopy = new ArrayList(); - final ArrayList urisCopy = new ArrayList(); - if (paths != null) { - pathsCopy.addAll(paths); - } - if (uris != null) { - urisCopy.addAll(uris); - } - new Thread(new Runnable() { - @Override - public void run() { - ArrayList sendAsDocuments = null; - ArrayList sendAsDocumentsOriginal = null; - int count = !pathsCopy.isEmpty() ? pathsCopy.size() : urisCopy.size(); - String path = null; - Uri uri = null; - for (int a = 0; a < count; a++) { - if (!pathsCopy.isEmpty()) { - path = pathsCopy.get(a); - } else if (!urisCopy.isEmpty()) { - uri = urisCopy.get(a); - } - - String originalPath = path; - String tempPath = path; - if (tempPath == null && uri != null) { - tempPath = Utilities.getPath(uri); - originalPath = uri.toString(); - } - - boolean isGif = false; - if (tempPath != null && tempPath.endsWith(".gif")) { - isGif = true; - } else if (tempPath == null && uri != null) { - isGif = MediaController.isGif(uri); - if (isGif) { - originalPath = uri.toString(); - tempPath = MediaController.copyDocumentToCache(uri, "gif"); - } - } - - if (isGif) { - if (sendAsDocuments == null) { - sendAsDocuments = new ArrayList(); - sendAsDocumentsOriginal = new ArrayList(); - } - sendAsDocuments.add(tempPath); - sendAsDocumentsOriginal.add(originalPath); - } else { - if (tempPath != null) { - File temp = new File(tempPath); - originalPath += temp.length() + "_" + temp.lastModified(); - } else { - originalPath = null; - } - TLRPC.TL_photo photo = (TLRPC.TL_photo)MessagesStorage.getInstance().getSentFile(originalPath, currentEncryptedChat == null ? 0 : 3); - if (photo == null && uri != null) { - photo = (TLRPC.TL_photo)MessagesStorage.getInstance().getSentFile(Utilities.getPath(uri), currentEncryptedChat == null ? 0 : 3); - } - if (photo == null) { - photo = SendMessagesHelper.getInstance().generatePhotoSizes(path, uri); - } - if (photo != null) { - final String originalPathFinal = originalPath; - final TLRPC.TL_photo photoFinal = photo; - AndroidUtilities.RunOnUIThread(new Runnable() { - @Override - public void run() { - SendMessagesHelper.getInstance().sendMessage(photoFinal, originalPathFinal, dialog_id); - if (chatListView != null) { - chatListView.setSelectionFromTop(messages.size() - 1, -100000 - chatListView.getPaddingTop()); - } - if (paused) { - scrollToTopOnResume = true; - } - } - }); - } - } - } - if (sendAsDocuments != null && !sendAsDocuments.isEmpty()) { - for (int a = 0; a < sendAsDocuments.size(); a++) { - processSendingDocumentInternal(sendAsDocuments.get(a), sendAsDocumentsOriginal.get(a)); - } - } - } - }).start(); - } - - private void processSendingDocumentInternal(final String path, String originalPath) { - if (path == null || path.length() == 0) { - return; - } - final File f = new File(path); - if (!f.exists() || f.length() == 0) { - return; - } - - String name = f.getName(); - if (name == null) { - name = "noname"; - } - String ext = ""; - int idx = path.lastIndexOf("."); - if (idx != -1) { - ext = path.substring(idx + 1); - } - if (originalPath != null) { - originalPath += "" + f.length(); - } - - TLRPC.TL_document document = (TLRPC.TL_document)MessagesStorage.getInstance().getSentFile(originalPath, currentEncryptedChat == null ? 1 : 4); - if (document == null && !path.equals(originalPath)) { - document = (TLRPC.TL_document)MessagesStorage.getInstance().getSentFile(path + f.length(), currentEncryptedChat == null ? 1 : 4); - } - if (document == null) { - document = new TLRPC.TL_document(); - document.id = 0; - document.user_id = UserConfig.getClientUserId(); - document.date = ConnectionsManager.getInstance().getCurrentTime(); - document.file_name = name; - document.size = (int)f.length(); - document.dc_id = 0; - if (ext.length() != 0) { - MimeTypeMap myMime = MimeTypeMap.getSingleton(); - String mimeType = myMime.getMimeTypeFromExtension(ext.toLowerCase()); - if (mimeType != null) { - document.mime_type = mimeType; - } else { - document.mime_type = "application/octet-stream"; - } - } else { - document.mime_type = "application/octet-stream"; - } - if (document.mime_type.equals("image/gif")) { - try { - Bitmap bitmap = ImageLoader.loadBitmap(f.getAbsolutePath(), null, 90, 90); - if (bitmap != null) { - document.thumb = ImageLoader.scaleAndSaveImage(bitmap, 90, 90, 55, currentEncryptedChat != null); - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - if (document.thumb == null) { - document.thumb = new TLRPC.TL_photoSizeEmpty(); - document.thumb.type = "s"; - } - } - - final TLRPC.TL_document documentFinal = document; - final String originalPathFinal = originalPath; - AndroidUtilities.RunOnUIThread(new Runnable() { - @Override - public void run() { - SendMessagesHelper.getInstance().sendMessage(documentFinal, originalPathFinal, path, dialog_id); - if (chatListView != null) { - chatListView.setSelectionFromTop(messages.size() - 1, -100000 - chatListView.getPaddingTop()); - } - if (paused) { - scrollToTopOnResume = true; - } - } - }); - } - - public void processSendingDocument(String path, String originalPath) { - if (path == null || originalPath == null) { - return; - } - ArrayList paths = new ArrayList(); - ArrayList originalPaths = new ArrayList(); - paths.add(path); - originalPaths.add(originalPath); - processSendingDocuments(paths, originalPaths); - } - - public void processSendingDocuments(final ArrayList paths, final ArrayList originalPaths) { - if (paths == null && originalPaths == null || paths != null && originalPaths != null && paths.size() != originalPaths.size()) { - return; - } - new Thread(new Runnable() { - @Override - public void run() { - for (int a = 0; a < paths.size(); a++) { - processSendingDocumentInternal(paths.get(a), originalPaths.get(a)); - } - } - }).start(); - } - - public void processSendingVideo(final String videoPath, final long estimatedSize, final long duration, final int width, final int height, final TLRPC.VideoEditedInfo videoEditedInfo) { - if (videoPath == null || videoPath.length() == 0) { - return; - } - new Thread(new Runnable() { - @Override - public void run() { - String path = videoPath; - String originalPath = videoPath; - File temp = new File(originalPath); - originalPath += temp.length() + "_" + temp.lastModified(); - if (videoEditedInfo != null) { - originalPath += duration + "_" + videoEditedInfo.startTime + "_" + videoEditedInfo.endTime; - } - TLRPC.TL_video video = (TLRPC.TL_video)MessagesStorage.getInstance().getSentFile(originalPath, currentEncryptedChat == null ? 2 : 5); - if (video == null) { - Bitmap thumb = ThumbnailUtils.createVideoThumbnail(videoPath, MediaStore.Video.Thumbnails.MINI_KIND); - TLRPC.PhotoSize size = ImageLoader.scaleAndSaveImage(thumb, 90, 90, 55, currentEncryptedChat != null); - video = new TLRPC.TL_video(); - video.thumb = size; - if (video.thumb == null) { - video.thumb = new TLRPC.TL_photoSizeEmpty(); - video.thumb.type = "s"; - } else { - video.thumb.type = "s"; - } - video.caption = ""; - video.mime_type = "video/mp4"; - video.id = 0; - UserConfig.saveConfig(false); - - if (videoEditedInfo != null) { - video.duration = (int)(duration / 1000); - if (videoEditedInfo.rotationValue == 90 || videoEditedInfo.rotationValue == 270) { - video.w = height; - video.h = width; - } else { - video.w = width; - video.h = height; - } - video.size = (int)estimatedSize; - video.videoEditedInfo = videoEditedInfo; - String fileName = Integer.MIN_VALUE + "_" + UserConfig.lastLocalId + ".mp4"; - UserConfig.lastLocalId--; - File cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName); - UserConfig.saveConfig(false); - path = cacheFile.getAbsolutePath(); - } else { - if (temp != null && temp.exists()) { - video.size = (int) temp.length(); - } - boolean infoObtained = false; - if (Build.VERSION.SDK_INT >= 14) { - MediaMetadataRetriever mediaMetadataRetriever = null; - try { - mediaMetadataRetriever = new MediaMetadataRetriever(); - mediaMetadataRetriever.setDataSource(videoPath); - String width = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH); - if (width != null) { - video.w = Integer.parseInt(width); - } - String height = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT); - if (height != null) { - video.h = Integer.parseInt(height); - } - String duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); - if (duration != null) { - video.duration = (int) Math.ceil(Long.parseLong(duration) / 1000.0f); - } - infoObtained = true; - } catch (Exception e) { - FileLog.e("tmessages", e); - } finally { - try { - if (mediaMetadataRetriever != null) { - mediaMetadataRetriever.release(); - mediaMetadataRetriever = null; - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - } - if (!infoObtained) { - try { - MediaPlayer mp = MediaPlayer.create(ApplicationLoader.applicationContext, Uri.fromFile(new File(videoPath))); - if (mp != null) { - video.duration = (int) Math.ceil(mp.getDuration() / 1000.0f); - video.w = mp.getVideoWidth(); - video.h = mp.getVideoHeight(); - mp.release(); - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - } - } - - final TLRPC.TL_video videoFinal = video; - final String originalPathFinal = originalPath; - final String finalPath = path; - AndroidUtilities.RunOnUIThread(new Runnable() { - @Override - public void run() { - SendMessagesHelper.getInstance().sendMessage(videoFinal, originalPathFinal, finalPath, dialog_id); - if (chatListView != null) { - chatListView.setSelectionFromTop(messages.size() - 1, -100000 - chatListView.getPaddingTop()); - } - if (paused) { - scrollToTopOnResume = true; - } - } - }); - } - }).start(); - } - @SuppressWarnings("unchecked") @Override public void didReceivedNotification(int id, final Object... args) { @@ -2180,6 +1848,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (did == dialog_id) { boolean updateChat = false; + boolean hasFromMe = false; ArrayList arr = (ArrayList)args[1]; if (!unread_end_reached) { @@ -2245,6 +1914,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (obj.isOut()) { removeUnreadPlane(false); + hasFromMe = true; } if (!obj.isOut() && unreadMessageObject != null) { @@ -2299,7 +1969,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (endReached) { lastVisible++; } - if (lastVisible == oldCount) { + if (lastVisible == oldCount || hasFromMe) { if (!firstLoading) { if (paused) { scrollToTopOnResume = true; @@ -3385,6 +3055,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ((ChatBaseCell)view).setDelegate(new ChatBaseCell.ChatBaseCellDelegate() { @Override public void didPressedUserAvatar(ChatBaseCell cell, TLRPC.User user) { + if (actionBarLayer.isActionModeShowed()) { + processRowSelect(cell); + return; + } if (user != null && user.id != UserConfig.getClientUserId()) { Bundle args = new Bundle(); args.putInt("user_id", user.id); @@ -3496,6 +3170,58 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not createMenu(cell, true); } }); + } else if (view instanceof ChatContactCell) { + ((ChatContactCell)view).setContactDelegate(new ChatContactCell.ChatContactCellDelegate() { + @Override + public void didClickAddButton(ChatContactCell cell, TLRPC.User user) { + if (actionBarLayer.isActionModeShowed()) { + processRowSelect(cell); + return; + } + Bundle args = new Bundle(); + args.putInt("user_id", message.messageOwner.media.user_id); + args.putString("phone", message.messageOwner.media.phone_number); + presentFragment(new ContactAddActivity(args)); + } + + @Override + public void didClickPhone(ChatContactCell cell) { + if (actionBarLayer.isActionModeShowed()) { + processRowSelect(cell); + return; + } + final MessageObject messageObject = cell.getMessageObject(); + if (getParentActivity() == null || messageObject.messageOwner.media.phone_number == null || messageObject.messageOwner.media.phone_number.length() == 0) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setItems(new CharSequence[] {LocaleController.getString("Copy", R.string.Copy), LocaleController.getString("Call", R.string.Call)}, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (i == 1) { + try { + Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + messageObject.messageOwner.media.phone_number)); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + getParentActivity().startActivity(intent); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } else if (i == 0) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + android.text.ClipboardManager clipboard = (android.text.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + clipboard.setText(messageObject.messageOwner.media.phone_number); + } else { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText("label", messageObject.messageOwner.media.phone_number); + clipboard.setPrimaryClip(clip); + } + } + } + } + ); + showAlertDialog(builder); + } + }); } } else if (view instanceof ChatActionCell) { ((ChatActionCell)view).setDelegate(new ChatActionCell.ChatActionCellDelegate() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index 11817f09..f61b30d5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -670,7 +670,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa } } else { actionBarLayout.presentFragment(fragment, true); - fragment.processSendingVideo(videoPath, 0, 0, 0, 0, null); + SendMessagesHelper.prepareSendingVideo(videoPath, 0, 0, 0, 0, null, dialog_id); } } else { actionBarLayout.presentFragment(fragment, true); @@ -678,10 +678,10 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa fragment.processSendingText(sendingText); } if (photoPathsArray != null) { - fragment.processSendingPhotos(null, photoPathsArray); + SendMessagesHelper.prepareSendingPhotos(null, photoPathsArray, dialog_id); } if (documentsPathsArray != null) { - fragment.processSendingDocuments(documentsPathsArray, documentsOriginalPathsArray); + SendMessagesHelper.prepareSendingDocuments(documentsPathsArray, documentsOriginalPathsArray, dialog_id); } if (contactsToSend != null && !contactsToSend.isEmpty()) { for (TLRPC.User user : contactsToSend) { @@ -1190,7 +1190,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa buttonLayoutTablet.setVisibility(View.VISIBLE); backgroundTablet.setVisibility(View.VISIBLE); } - } else if (layout == layersActionBarLayout && actionBarLayout.fragmentsStack.isEmpty()) { + } else if (layout == layersActionBarLayout && actionBarLayout.fragmentsStack.isEmpty() && layersActionBarLayout.fragmentsStack.size() == 1) { onFinish(); finish(); return false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java index 8a0b4e9e..ce0c21d9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java @@ -853,7 +853,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter if (user != null && user.phone != null && user.phone.length() != 0) { textView.setText(PhoneFormat.getInstance().format("+" + user.phone)); } else { - textView.setText("Unknown"); + textView.setText(LocaleController.getString("Unknown", R.string.Unknown)); } divider.setVisibility(View.INVISIBLE); } else if (i == notificationRow) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsBlockedUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsBlockedUsersActivity.java index b1f888ca..b2e169a6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsBlockedUsersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsBlockedUsersActivity.java @@ -249,7 +249,7 @@ public class SettingsBlockedUsersActivity extends BaseFragment implements Notifi ((ChatOrUserCell)view).useSeparator = true; } TLRPC.User user = MessagesController.getInstance().getUser(MessagesController.getInstance().blockedUsers.get(i)); - ((ChatOrUserCell)view).setData(user, null, null, null, user.phone != null && user.phone.length() != 0 ? PhoneFormat.getInstance().format("+" + user.phone) : "Unknown"); + ((ChatOrUserCell)view).setData(user, null, null, null, user.phone != null && user.phone.length() != 0 ? PhoneFormat.getInstance().format("+" + user.phone) : LocaleController.getString("Unknown", R.string.Unknown)); } else if (type == 1) { if (view == null) { LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java index 84a121a0..0d41355f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java @@ -608,7 +608,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen if (user.phone != null && user.phone.length() != 0) { textView.setText(PhoneFormat.getInstance().format("+" + user.phone)); } else { - textView.setText("Unknown"); + textView.setText(LocaleController.getString("Unknown", R.string.Unknown)); } divider.setVisibility(View.INVISIBLE); detailTextView.setText(LocaleController.getString("PhoneMobile", R.string.PhoneMobile)); diff --git a/TMessagesProj/src/main/res/layout/chat_group_incoming_contact_layout.xml b/TMessagesProj/src/main/res/layout/chat_group_incoming_contact_layout.xml deleted file mode 100644 index 0445491b..00000000 --- a/TMessagesProj/src/main/res/layout/chat_group_incoming_contact_layout.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/layout/chat_incoming_contact_layout.xml b/TMessagesProj/src/main/res/layout/chat_incoming_contact_layout.xml deleted file mode 100644 index d7643a8a..00000000 --- a/TMessagesProj/src/main/res/layout/chat_incoming_contact_layout.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/layout/chat_outgoing_contact_layout.xml b/TMessagesProj/src/main/res/layout/chat_outgoing_contact_layout.xml deleted file mode 100644 index f047bc8b..00000000 --- a/TMessagesProj/src/main/res/layout/chat_outgoing_contact_layout.xml +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-ar/strings.xml b/TMessagesProj/src/main/res/values-ar/strings.xml index 31cc29be..f0367e4e 100644 --- a/TMessagesProj/src/main/res/values-ar/strings.xml +++ b/TMessagesProj/src/main/res/values-ar/strings.xml @@ -197,6 +197,7 @@ عداد التدمير الذاتي إيقاف هذه الصورة هي تصور لمفتاح التشفير لهذه المحادثة السرية مع ]]>%1$s]]>.
    ]]>إذا كانت مطابقة للصورة التي في جهاز ]]>%2$s]]>, فمحادثتكم آمنة ٢٠٠٪.
    ]]>للمزيد نرجو الذهاب إلى telegram.org
    + Unknown تم تعيين كافة الإشعارات افتراضيا حجم نص الرسائل diff --git a/TMessagesProj/src/main/res/values-de/strings.xml b/TMessagesProj/src/main/res/values-de/strings.xml index 1f5e3ece..478d7458 100644 --- a/TMessagesProj/src/main/res/values-de/strings.xml +++ b/TMessagesProj/src/main/res/values-de/strings.xml @@ -197,6 +197,7 @@ Selbstzerstörungs-Timer Aus Das ist eine Darstellung des Schlüssels für den Geheimen Chat mit ]]>%1$s]]>.
    ]]>Wenn dieses Bild auf ]]>%2$s\s]]>s Telefon genau so aussieht, ist euer Chat zu 200%% sicher.
    ]]>Erfahre mehr auf telegram.org
    + Unknown Alle Einstellungen für Mitteilungen zurücksetzen Textgröße für Nachrichten diff --git a/TMessagesProj/src/main/res/values-es/strings.xml b/TMessagesProj/src/main/res/values-es/strings.xml index a305a69f..920f5533 100644 --- a/TMessagesProj/src/main/res/values-es/strings.xml +++ b/TMessagesProj/src/main/res/values-es/strings.xml @@ -197,6 +197,7 @@ Autodestrucción Apagada Esta imagen es una visualización de la clave de cifrado para el chat secreto con ]]>%1$s]]>.
    ]]>Si esta imagen se ve igual en el teléfono de ]]>%2$s]]>, tu chat es seguro en un 200%%.
    ]]>Aprende más en telegram.org
    + Unknown Restablecer las notificaciones Tamaño del texto diff --git a/TMessagesProj/src/main/res/values-it/strings.xml b/TMessagesProj/src/main/res/values-it/strings.xml index ab97be9d..581b0807 100644 --- a/TMessagesProj/src/main/res/values-it/strings.xml +++ b/TMessagesProj/src/main/res/values-it/strings.xml @@ -197,6 +197,7 @@ Timer di autodistruzione Spento Questa immagine è una visualizzazione della chiave di cifratura per questa chat segreta con ]]>%1$s]]>.
    ]]>Se questa immagine è uguale sul telefono di ]]>%2$s]]>, la chat è sicura al 200%%.
    ]]>Per saperne di più, visita Telegram.org
    + Unknown Ripristina tutte le impostazioni di notifica predefinite Dimensione testo messaggi diff --git a/TMessagesProj/src/main/res/values-ko/strings.xml b/TMessagesProj/src/main/res/values-ko/strings.xml index b17838d1..e44c83b9 100644 --- a/TMessagesProj/src/main/res/values-ko/strings.xml +++ b/TMessagesProj/src/main/res/values-ko/strings.xml @@ -197,6 +197,7 @@ 자동삭제 타이머 해제 이 이미지는 ]]>%1$s]]>님과의 비밀대화에 사용 중인 암호화 키의 모습입니다.
    ]]>이 이미지가 ]]>%2$s]]>님의 암호화 키와 똑같다면 대화는 200%% 안전합니다.
    ]]>더 자세한 사항은 telegram.org 를 참고해 주세요.
    + Unknown 모든 알림 설정이 초기화되었습니다 채팅 글자 크기 diff --git a/TMessagesProj/src/main/res/values-nl/strings.xml b/TMessagesProj/src/main/res/values-nl/strings.xml index a1461457..eb929997 100644 --- a/TMessagesProj/src/main/res/values-nl/strings.xml +++ b/TMessagesProj/src/main/res/values-nl/strings.xml @@ -197,6 +197,7 @@ Zelfvernietigingstimer Uit Dit is een weergave van de encryptiesleutel voor deze geheime chat met ]]>%1$s]]>.
    ]]>Als deze afbeelding er bij ]]>%2$s]]> hetzelfde uitziet, is jullie gesprek 200%% beveiligd.
    ]]>Lees meer op telegram.org.
    + Unknown Alle meldingsinstellingen herstellen Tekstgrootte berichten diff --git a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml index ae5634e1..8a04e1e6 100644 --- a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml @@ -197,6 +197,7 @@ Tempo de autodestruição Desativado Esta imagem é uma visualização da chave criptográfica para esta conversa secreta com ]]>%1$s]]>.
    ]]>Se esta imagem aparecer da mesma forma no telefone de ]]>%2$s\'s]]>, sua conversa é 200%% segura.
    ]]>Saiba mais em telegram.org
    + Unknown Restaurar todas as configurações de notificação Tamanho do texto nas mensagens diff --git a/TMessagesProj/src/main/res/values-pt-rPT/strings.xml b/TMessagesProj/src/main/res/values-pt-rPT/strings.xml index 90d884f2..844c5925 100644 --- a/TMessagesProj/src/main/res/values-pt-rPT/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rPT/strings.xml @@ -197,6 +197,7 @@ Tempo de autodestruição Desativado Esta imagem é uma visualização da chave criptográfica para esta conversa secreta com ]]>%1$s]]>.
    ]]>Se esta imagem aparecer da mesma forma no telefone de ]]>%2$s\'s]]>, sua conversa é 200%% segura.
    ]]>Saiba mais em telegram.org
    + Unknown Restaurar todas as configurações de notificação Tamanho do texto nas mensagens diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index 3dce45be..67d833a2 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -197,6 +197,7 @@ Self-Destruct Timer Off This image is a visualization of the encryption key for this secret chat with ]]>%1$s]]>.
    ]]>If this image looks the same on ]]>%2$s\'s]]> phone, your chat is 200%% secure.
    ]]>Learn more at telegram.org
    + Unknown Reset all notification settings to default Messages Text Size From bc76df2f9947a6e55a9defece97cdc5bae4d0458 Mon Sep 17 00:00:00 2001 From: DrKLO Date: Fri, 17 Oct 2014 22:29:13 +0400 Subject: [PATCH 09/18] Update to layer 18, usernames support, UI improvements --- TMessagesProj/build.gradle | 2 +- .../telegram/android/MessagesController.java | 42 +++- .../org/telegram/android/MessagesStorage.java | 3 + .../messenger/ConnectionsManager.java | 37 +-- .../org/telegram/messenger/FileLoader.java | 12 +- .../org/telegram/messenger/TLClassStore.java | 7 + .../java/org/telegram/messenger/TLRPC.java | 230 +++++++++++++++++- .../ContactsActivitySearchAdapter.java | 128 +++++++--- .../org/telegram/ui/Cells/ChatAudioCell.java | 37 ++- .../telegram/ui/Cells/ChatContactCell.java | 50 ++-- .../org/telegram/ui/ContactsActivity.java | 7 + .../org/telegram/ui/SettingsActivity.java | 45 ++-- .../ui/SettingsChangeNameActivity.java | 9 +- .../ui/SettingsChangeUsernameActivity.java | 216 ++++++++++++++++ .../org/telegram/ui/UserProfileActivity.java | 28 ++- .../res/drawable-hdpi/addcontact_blue.png | Bin 0 -> 966 bytes .../res/drawable-hdpi/addcontact_green.png | Bin 0 -> 966 bytes .../res/drawable-hdpi/ic_ab_add_member.png | Bin 1700 -> 0 bytes .../res/drawable-ldpi/addcontact_blue.png | Bin 0 -> 954 bytes .../res/drawable-ldpi/addcontact_green.png | Bin 0 -> 972 bytes .../res/drawable-ldpi/ic_ab_add_member.png | Bin 1360 -> 0 bytes .../res/drawable-mdpi/addcontact_blue.png | Bin 0 -> 956 bytes .../res/drawable-mdpi/addcontact_green.png | Bin 0 -> 956 bytes .../res/drawable-mdpi/ic_ab_add_member.png | Bin 1457 -> 0 bytes .../res/drawable-xhdpi/addcontact_blue.png | Bin 0 -> 982 bytes .../res/drawable-xhdpi/addcontact_green.png | Bin 0 -> 982 bytes .../res/drawable-xhdpi/ic_ab_add_member.png | Bin 1958 -> 0 bytes .../res/drawable-xxhdpi/addcontact_blue.png | Bin 0 -> 1014 bytes .../res/drawable-xxhdpi/addcontact_green.png | Bin 0 -> 1012 bytes .../res/drawable-xxhdpi/ic_ab_add_member.png | Bin 2456 -> 0 bytes .../chat_profile_change_name_layout.xml | 4 +- .../layout/settings_change_name_layout.xml | 4 +- .../src/main/res/values-ar/strings.xml | 7 +- .../src/main/res/values-de/strings.xml | 7 +- .../src/main/res/values-es/strings.xml | 7 +- .../src/main/res/values-it/strings.xml | 7 +- .../src/main/res/values-ko/strings.xml | 7 +- .../src/main/res/values-nl/strings.xml | 7 +- .../src/main/res/values-pt-rBR/strings.xml | 7 +- .../src/main/res/values-pt-rPT/strings.xml | 7 +- TMessagesProj/src/main/res/values/strings.xml | 7 +- 41 files changed, 793 insertions(+), 131 deletions(-) create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/addcontact_blue.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/addcontact_green.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/ic_ab_add_member.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/addcontact_blue.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/addcontact_green.png delete mode 100644 TMessagesProj/src/main/res/drawable-ldpi/ic_ab_add_member.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/addcontact_blue.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/addcontact_green.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/ic_ab_add_member.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/addcontact_blue.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/addcontact_green.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/ic_ab_add_member.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/addcontact_blue.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/addcontact_green.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/ic_ab_add_member.png diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index 235ad19b..f776b919 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -80,7 +80,7 @@ android { defaultConfig { minSdkVersion 8 targetSdkVersion 19 - versionCode 358 + versionCode 359 versionName "1.9.5" } } diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java index b4e1a6f4..722277b2 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java @@ -67,6 +67,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter private long updatesStartWaitTime = 0; public ArrayList delayedEncryptedChatUpdates = new ArrayList(); private boolean startingSecretChat = false; + private ArrayList loadingFullUsers = new ArrayList(); + private ArrayList loadedFullUsers = new ArrayList(); private boolean gettingNewDeleteTask = false; private int currentDeletingTaskTime = 0; @@ -318,6 +320,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter delayedEncryptedChatUpdates.clear(); blockedUsers.clear(); sendingTypings.clear(); + loadingFullUsers.clear(); + loadedFullUsers.clear(); updatesStartWaitTime = 0; currentDeletingTaskTime = 0; @@ -389,6 +393,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter users.put(user.id, user); if (user.id == UserConfig.getClientUserId()) { UserConfig.setCurrentUser(user); + UserConfig.saveConfig(true); } if (oldUser != null && user.status != null && oldUser.status != null && user.status.expires != oldUser.status.expires) { return true; @@ -459,10 +464,15 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } + public void cancelLoadFullUser(int uid) { + loadingFullUsers.remove((Integer) uid); + } + public void loadFullUser(final TLRPC.User user, final int classGuid) { - if (user == null) { + if (user == null || loadingFullUsers.contains(user.id) || loadedFullUsers.contains(user.id)) { return; } + loadingFullUsers.add(user.id); TLRPC.TL_users_getFullUser req = new TLRPC.TL_users_getFullUser(); req.id = getInputUser(user); long reqId = ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() { @@ -472,10 +482,24 @@ public class MessagesController implements NotificationCenter.NotificationCenter AndroidUtilities.RunOnUIThread(new Runnable() { @Override public void run() { + loadingFullUsers.remove((Integer)user.id); + loadedFullUsers.add(user.id); + String names = user.first_name + user.last_name + user.username; TLRPC.TL_userFull userFull = (TLRPC.TL_userFull)response; ArrayList users = new ArrayList(); users.add(userFull.user); putUsers(users, false); + MessagesStorage.getInstance().putUsersAndChats(users, null, false, true); + if (!names.equals(userFull.user.first_name + userFull.user.last_name + userFull.user.username)) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_NAME); + } + } + }); + } else { + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + loadingFullUsers.remove((Integer)user.id); } }); } @@ -3153,6 +3177,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter newChat.user_id = exist.user_id; newChat.auth_key = exist.auth_key; newChat.ttl = exist.ttl; + newChat.seq_in = exist.seq_in; + newChat.seq_out = exist.seq_out; putEncryptedChat(newChat, false); } MessagesStorage.getInstance().updateEncryptedChat(newChat); @@ -3189,6 +3215,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter }); } else if (update instanceof TLRPC.TL_updateNotifySettings) { updatesOnMainThread.add(update); + } else if (update instanceof TLRPC.TL_updateServiceNotification) { + //TODO } } if (!messages.isEmpty()) { @@ -3257,9 +3285,11 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (currentUser != null) { currentUser.first_name = update.first_name; currentUser.last_name = update.last_name; + currentUser.username = update.username; } toDbUser.first_name = update.first_name; toDbUser.last_name = update.last_name; + toDbUser.username = update.username; dbUsers.add(toDbUser); } else if (update instanceof TLRPC.TL_updateUserPhoto) { if (currentUser != null) { @@ -3786,6 +3816,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } }); + } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionResend) { + } else { return null; } @@ -3832,12 +3864,15 @@ public class MessagesController implements NotificationCenter.NotificationCenter long fingerprint = Utilities.bytesToLong(authKeyId); if (encryptedChat.key_fingerprint == fingerprint) { encryptedChat.auth_key = authKey; + encryptedChat.seq_in = 0; + encryptedChat.seq_out = 1; MessagesStorage.getInstance().updateEncryptedChat(encryptedChat); AndroidUtilities.RunOnUIThread(new Runnable() { @Override public void run() { putEncryptedChat(encryptedChat, false); NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, encryptedChat); + SendMessagesHelper.getInstance().sendNotifyLayerMessage(encryptedChat); } }); } else { @@ -3845,6 +3880,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter newChat.id = encryptedChat.id; newChat.user_id = encryptedChat.user_id; newChat.auth_key = encryptedChat.auth_key; + newChat.seq_in = encryptedChat.seq_in; + newChat.seq_out = encryptedChat.seq_out; MessagesStorage.getInstance().updateEncryptedChat(newChat); AndroidUtilities.RunOnUIThread(new Runnable() { @Override @@ -3952,12 +3989,15 @@ public class MessagesController implements NotificationCenter.NotificationCenter final TLRPC.EncryptedChat newChat = (TLRPC.EncryptedChat) response; newChat.auth_key = encryptedChat.auth_key; newChat.user_id = encryptedChat.user_id; + newChat.seq_in = encryptedChat.seq_in; + newChat.seq_out = encryptedChat.seq_out; MessagesStorage.getInstance().updateEncryptedChat(newChat); AndroidUtilities.RunOnUIThread(new Runnable() { @Override public void run() { putEncryptedChat(newChat, false); NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, newChat); + SendMessagesHelper.getInstance().sendNotifyLayerMessage(newChat); } }); } diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java index 09dffff1..9260ba4a 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java @@ -109,6 +109,7 @@ public class MessagesStorage { database.executeFast("CREATE TABLE blocked_users(uid INTEGER PRIMARY KEY)").stepThis().dispose(); database.executeFast("CREATE TABLE download_queue(uid INTEGER, type INTEGER, date INTEGER, data BLOB, PRIMARY KEY (uid, type));").stepThis().dispose(); database.executeFast("CREATE TABLE dialog_settings(did INTEGER PRIMARY KEY, flags INTEGER);").stepThis().dispose(); + database.executeFast("CREATE TABLE messages_seq(mid INTEGER PRIMARY KEY, seq_in INTEGER, seq_out INTEGER);").stepThis().dispose(); //database.executeFast("CREATE TABLE attach_data(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose(); database.executeFast("CREATE TABLE user_contacts_v6(uid INTEGER PRIMARY KEY, fname TEXT, sname TEXT)").stepThis().dispose(); @@ -290,6 +291,7 @@ public class MessagesStorage { version = 6; } if (version == 6 && version < 7) { + database.executeFast("CREATE TABLE IF NOT EXISTS messages_seq(mid INTEGER PRIMARY KEY, seq_in INTEGER, seq_out INTEGER);").stepThis().dispose(); database.executeFast("ALTER TABLE enc_chats ADD COLUMN layer INTEGER default 0").stepThis().dispose(); database.executeFast("ALTER TABLE enc_chats ADD COLUMN seq_in INTEGER default 0").stepThis().dispose(); database.executeFast("ALTER TABLE enc_chats ADD COLUMN seq_out INTEGER default 0").stepThis().dispose(); @@ -2956,6 +2958,7 @@ public class MessagesStorage { if (updateUser.first_name != null && updateUser.last_name != null) { user.first_name = updateUser.first_name; user.last_name = updateUser.last_name; + user.username = updateUser.username; } else if (updateUser.photo != null) { user.photo = updateUser.photo; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java b/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java index 755deabc..a0946ca6 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java @@ -833,7 +833,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. } object = invoke; } - TLRPC.invokeWithLayer17 invoke = new TLRPC.invokeWithLayer17(); + TLRPC.invokeWithLayer18 invoke = new TLRPC.invokeWithLayer18(); invoke.query = object; FileLog.d("wrap in layer", "" + object); return invoke; @@ -1386,7 +1386,9 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. if (rawRequest != null && (rawRequest instanceof TLRPC.TL_messages_sendMessage || rawRequest instanceof TLRPC.TL_messages_sendMedia || rawRequest instanceof TLRPC.TL_messages_forwardMessages || - rawRequest instanceof TLRPC.TL_messages_sendEncrypted)) { + rawRequest instanceof TLRPC.TL_messages_sendEncrypted || + rawRequest instanceof TLRPC.TL_messages_sendEncryptedFile || + rawRequest instanceof TLRPC.TL_messages_sendEncryptedService)) { if (rawRequest instanceof TLRPC.TL_messages_sendMessage) { hasSendMessage = true; @@ -1404,7 +1406,9 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. if (currentRawRequest instanceof TLRPC.TL_messages_sendMessage || currentRawRequest instanceof TLRPC.TL_messages_sendMedia || currentRawRequest instanceof TLRPC.TL_messages_forwardMessages || - currentRawRequest instanceof TLRPC.TL_messages_sendEncrypted) { + currentRawRequest instanceof TLRPC.TL_messages_sendEncrypted || + currentRawRequest instanceof TLRPC.TL_messages_sendEncryptedFile || + currentRawRequest instanceof TLRPC.TL_messages_sendEncryptedService) { currentRequests.add(currentMessage.msg_id); } } @@ -1414,7 +1418,9 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. if (request.rawRequest instanceof TLRPC.TL_messages_sendMessage || request.rawRequest instanceof TLRPC.TL_messages_sendMedia || request.rawRequest instanceof TLRPC.TL_messages_forwardMessages || - request.rawRequest instanceof TLRPC.TL_messages_sendEncrypted) { + request.rawRequest instanceof TLRPC.TL_messages_sendEncrypted || + request.rawRequest instanceof TLRPC.TL_messages_sendEncryptedFile || + request.rawRequest instanceof TLRPC.TL_messages_sendEncryptedService) { if (!currentRequests.contains(request.runningMessageId)) { maxRequestId = Math.max(maxRequestId, request.runningMessageId); } @@ -1608,12 +1614,12 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. TLRPC.TL_protoMessage message = networkMessage.protoMessage; if (BuildVars.DEBUG_VERSION) { - if (message.body instanceof TLRPC.invokeWithLayer17) { - FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer17)message.body).query); + if (message.body instanceof TLRPC.invokeWithLayer18) { + FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer18)message.body).query); } else if (message.body instanceof TLRPC.initConnection) { TLRPC.initConnection r = (TLRPC.initConnection)message.body; - if (r.query instanceof TLRPC.invokeWithLayer17) { - FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer17)r.query).query); + if (r.query instanceof TLRPC.invokeWithLayer18) { + FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer18)r.query).query); } else { FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + r.query); } @@ -1648,12 +1654,12 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. TLRPC.TL_protoMessage message = networkMessage.protoMessage; containerMessages.add(message); if (BuildVars.DEBUG_VERSION) { - if (message.body instanceof TLRPC.invokeWithLayer17) { - FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer17)message.body).query); + if (message.body instanceof TLRPC.invokeWithLayer18) { + FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer18)message.body).query); } else if (message.body instanceof TLRPC.initConnection) { TLRPC.initConnection r = (TLRPC.initConnection)message.body; - if (r.query instanceof TLRPC.invokeWithLayer17) { - FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer17)r.query).query); + if (r.query instanceof TLRPC.invokeWithLayer18) { + FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer18)r.query).query); } else { FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + r.query); } @@ -2070,12 +2076,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. int errorCode = ((TLRPC.RpcError) resultContainer.result).error_code; if (errorCode == 500 || errorCode < 0) { - if ((request.flags & RPCRequest.RPCRequestClassFailOnServerErrors) != 0) { - if (request.serverFailureCount < 1) { - discardResponse = true; - request.runningMinStartTime = request.runningStartTime + 1; - } - } else { + if ((request.flags & RPCRequest.RPCRequestClassFailOnServerErrors) == 0) { discardResponse = true; int delay = Math.min(1, request.serverFailureCount * 2); request.runningMinStartTime = request.runningStartTime + delay; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java index f67e955f..be06766b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java @@ -176,7 +176,7 @@ public class FileLoader { } if (small) { currentUploadSmallOperationsCount--; - if (currentUploadSmallOperationsCount < 2) { + if (currentUploadSmallOperationsCount < 1) { FileUploadOperation operation = uploadSmallOperationQueue.poll(); if (operation != null) { currentUploadSmallOperationsCount++; @@ -185,7 +185,7 @@ public class FileLoader { } } else { currentUploadOperationsCount--; - if (currentUploadOperationsCount < 2) { + if (currentUploadOperationsCount < 1) { FileUploadOperation operation = uploadOperationQueue.poll(); if (operation != null) { currentUploadOperationsCount++; @@ -227,7 +227,7 @@ public class FileLoader { }); if (small) { currentUploadSmallOperationsCount--; - if (currentUploadSmallOperationsCount < 2) { + if (currentUploadSmallOperationsCount < 1) { FileUploadOperation operation = uploadSmallOperationQueue.poll(); if (operation != null) { currentUploadSmallOperationsCount++; @@ -236,7 +236,7 @@ public class FileLoader { } } else { currentUploadOperationsCount--; - if (currentUploadOperationsCount < 2) { + if (currentUploadOperationsCount < 1) { FileUploadOperation operation = uploadOperationQueue.poll(); if (operation != null) { currentUploadOperationsCount++; @@ -259,14 +259,14 @@ public class FileLoader { } }; if (small) { - if (currentUploadSmallOperationsCount < 2) { + if (currentUploadSmallOperationsCount < 1) { currentUploadSmallOperationsCount++; operation.start(); } else { uploadSmallOperationQueue.add(operation); } } else { - if (currentUploadOperationsCount < 2) { + if (currentUploadOperationsCount < 1) { currentUploadOperationsCount++; operation.start(); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TLClassStore.java b/TMessagesProj/src/main/java/org/telegram/messenger/TLClassStore.java index 2e2f9452..6b030372 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TLClassStore.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TLClassStore.java @@ -198,6 +198,7 @@ public class TLClassStore { classStore.put(TLRPC.TL_updateReadMessages.constructor, TLRPC.TL_updateReadMessages.class); classStore.put(TLRPC.TL_updateChatParticipantDelete.constructor, TLRPC.TL_updateChatParticipantDelete.class); classStore.put(TLRPC.TL_updateRestoreMessages.constructor, TLRPC.TL_updateRestoreMessages.class); + classStore.put(TLRPC.TL_updateServiceNotification.constructor, TLRPC.TL_updateServiceNotification.class); classStore.put(TLRPC.TL_updateNotifySettings.constructor, TLRPC.TL_updateNotifySettings.class); classStore.put(TLRPC.TL_updateUserTyping.constructor, TLRPC.TL_updateUserTyping.class); classStore.put(TLRPC.TL_updateChatUserTyping.constructor, TLRPC.TL_updateChatUserTyping.class); @@ -226,6 +227,7 @@ public class TLClassStore { classStore.put(TLRPC.TL_inputEncryptedFileEmpty.constructor, TLRPC.TL_inputEncryptedFileEmpty.class); classStore.put(TLRPC.TL_inputEncryptedFileUploaded.constructor, TLRPC.TL_inputEncryptedFileUploaded.class); classStore.put(TLRPC.TL_decryptedMessageActionFlushHistory.constructor, TLRPC.TL_decryptedMessageActionFlushHistory.class); + classStore.put(TLRPC.TL_decryptedMessageActionResend.constructor, TLRPC.TL_decryptedMessageActionResend.class); classStore.put(TLRPC.TL_decryptedMessageActionNotifyLayer.constructor, TLRPC.TL_decryptedMessageActionNotifyLayer.class); classStore.put(TLRPC.TL_decryptedMessageActionSetMessageTTL.constructor, TLRPC.TL_decryptedMessageActionSetMessageTTL.class); classStore.put(TLRPC.TL_decryptedMessageActionDeleteMessages.constructor, TLRPC.TL_decryptedMessageActionDeleteMessages.class); @@ -363,6 +365,11 @@ public class TLClassStore { classStore.put(TLRPC.TL_decryptedMessageService_old.constructor, TLRPC.TL_decryptedMessageService_old.class); classStore.put(TLRPC.TL_decryptedMessage_old.constructor, TLRPC.TL_decryptedMessage_old.class); classStore.put(TLRPC.TL_message_secret.constructor, TLRPC.TL_message_secret.class); + classStore.put(TLRPC.TL_userSelf_old.constructor, TLRPC.TL_userSelf_old.class); + classStore.put(TLRPC.TL_userContact_old.constructor, TLRPC.TL_userContact_old.class); + classStore.put(TLRPC.TL_userRequest_old.constructor, TLRPC.TL_userRequest_old.class); + classStore.put(TLRPC.TL_userForeign_old.constructor, TLRPC.TL_userForeign_old.class); + classStore.put(TLRPC.TL_userDeleted_old.constructor, TLRPC.TL_userDeleted_old.class); } static TLClassStore store = null; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java index f985df2c..b358aca1 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java @@ -2084,13 +2084,14 @@ public class TLRPC { } public static class TL_userContact extends User { - public static int constructor = 0xf2fb8319; + public static int constructor = 0xcab35e18; public void readParams(AbsSerializedData stream) { id = stream.readInt32(); first_name = stream.readString(); last_name = stream.readString(); + username = stream.readString(); access_hash = stream.readInt64(); phone = stream.readString(); photo = (UserProfilePhoto)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); @@ -2102,6 +2103,7 @@ public class TLRPC { stream.writeInt32(id); stream.writeString(first_name); stream.writeString(last_name); + stream.writeString(username); stream.writeInt64(access_hash); stream.writeString(phone); photo.serializeToStream(stream); @@ -2110,13 +2112,14 @@ public class TLRPC { } public static class TL_userRequest extends User { - public static int constructor = 0x22e8ceb0; + public static int constructor = 0xd9ccc4ef; public void readParams(AbsSerializedData stream) { id = stream.readInt32(); first_name = stream.readString(); last_name = stream.readString(); + username = stream.readString(); access_hash = stream.readInt64(); phone = stream.readString(); photo = (UserProfilePhoto)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); @@ -2128,6 +2131,7 @@ public class TLRPC { stream.writeInt32(id); stream.writeString(first_name); stream.writeString(last_name); + stream.writeString(username); stream.writeInt64(access_hash); stream.writeString(phone); photo.serializeToStream(stream); @@ -2136,13 +2140,14 @@ public class TLRPC { } public static class TL_userForeign extends User { - public static int constructor = 0x5214c89d; + public static int constructor = 0x75cf7a8; public void readParams(AbsSerializedData stream) { id = stream.readInt32(); first_name = stream.readString(); last_name = stream.readString(); + username = stream.readString(); access_hash = stream.readInt64(); photo = (UserProfilePhoto)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); status = (UserStatus)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); @@ -2153,6 +2158,7 @@ public class TLRPC { stream.writeInt32(id); stream.writeString(first_name); stream.writeString(last_name); + stream.writeString(username); stream.writeInt64(access_hash); photo.serializeToStream(stream); status.serializeToStream(stream); @@ -2160,13 +2166,14 @@ public class TLRPC { } public static class TL_userDeleted extends User { - public static int constructor = 0xb29ad7cc; + public static int constructor = 0xd6016d7a; public void readParams(AbsSerializedData stream) { id = stream.readInt32(); first_name = stream.readString(); last_name = stream.readString(); + username = stream.readString(); } public void serializeToStream(AbsSerializedData stream) { @@ -2174,17 +2181,19 @@ public class TLRPC { stream.writeInt32(id); stream.writeString(first_name); stream.writeString(last_name); + stream.writeString(username); } } public static class TL_userSelf extends User { - public static int constructor = 0x720535ec; + public static int constructor = 0x7007b451; public void readParams(AbsSerializedData stream) { id = stream.readInt32(); first_name = stream.readString(); last_name = stream.readString(); + username = stream.readString(); phone = stream.readString(); photo = (UserProfilePhoto)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); status = (UserStatus)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); @@ -2196,6 +2205,7 @@ public class TLRPC { stream.writeInt32(id); stream.writeString(first_name); stream.writeString(last_name); + stream.writeString(username); stream.writeString(phone); photo.serializeToStream(stream); status.serializeToStream(stream); @@ -3425,11 +3435,15 @@ public class TLRPC { public ArrayList messages = new ArrayList(); public int pts; public int version; + public String type; + public MessageMedia media; + public boolean popup; public NotifyPeer peer; public PeerNotifySettings notify_settings; public SendMessageAction action; public String first_name; public String last_name; + public String username; public int qts; public int id; public long random_id; @@ -3550,6 +3564,27 @@ public class TLRPC { } } + public static class TL_updateServiceNotification extends Update { + public static int constructor = 0x382dd3e4; + + public String message; + + public void readParams(AbsSerializedData stream) { + type = stream.readString(); + message = stream.readString(); + media = (MessageMedia)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); + popup = stream.readBool(); + } + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(type); + stream.writeString(message); + media.serializeToStream(stream); + stream.writeBool(popup); + } + } + public static class TL_updateNotifySettings extends Update { public static int constructor = 0xbec268ef; @@ -3601,13 +3636,14 @@ public class TLRPC { } public static class TL_updateUserName extends Update { - public static int constructor = 0xda22d9ad; + public static int constructor = 0xa7332b73; public void readParams(AbsSerializedData stream) { user_id = stream.readInt32(); first_name = stream.readString(); last_name = stream.readString(); + username = stream.readString(); } public void serializeToStream(AbsSerializedData stream) { @@ -3615,6 +3651,7 @@ public class TLRPC { stream.writeInt32(user_id); stream.writeString(first_name); stream.writeString(last_name); + stream.writeString(username); } } @@ -4037,6 +4074,8 @@ public class TLRPC { } public static class DecryptedMessageAction extends TLObject { + public int start_seq_no; + public int end_seq_no; public int layer; public int ttl_seconds; public ArrayList random_ids = new ArrayList(); @@ -4064,6 +4103,22 @@ public class TLRPC { } } + public static class TL_decryptedMessageActionResend extends DecryptedMessageAction { + public static int constructor = 0x511110b0; + + + public void readParams(AbsSerializedData stream) { + start_seq_no = stream.readInt32(); + end_seq_no = stream.readInt32(); + } + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(start_seq_no); + stream.writeInt32(end_seq_no); + } + } + public static class TL_decryptedMessageActionNotifyLayer extends DecryptedMessageAction { public static int constructor = 0xf3048883; @@ -4572,6 +4627,44 @@ public class TLRPC { } } + public static class TL_account_checkUsername extends TLObject { + public static int constructor = 0x2714d86c; + + public String username; + + public Class responseClass () { + return Bool.class; + } + + public void readParams(AbsSerializedData stream) { + username = stream.readString(); + } + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(username); + } + } + + public static class TL_account_updateUsername extends TLObject { + public static int constructor = 0x3e0bdd7c; + + public String username; + + public Class responseClass () { + return User.class; + } + + public void readParams(AbsSerializedData stream) { + username = stream.readString(); + } + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(username); + } + } + public static class InputAudio extends TLObject { public long id; public long access_hash; @@ -8363,6 +8456,126 @@ public class TLRPC { //manually created + public static class TL_userDeleted_old extends TL_userDeleted { + public static int constructor = 0xb29ad7cc; + + + public void readParams(AbsSerializedData stream) { + id = stream.readInt32(); + first_name = stream.readString(); + last_name = stream.readString(); + } + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeString(first_name); + stream.writeString(last_name); + } + } + + public static class TL_userForeign_old extends TL_userForeign { + public static int constructor = 0x5214c89d; + + + public void readParams(AbsSerializedData stream) { + id = stream.readInt32(); + first_name = stream.readString(); + last_name = stream.readString(); + access_hash = stream.readInt64(); + photo = (UserProfilePhoto)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); + status = (UserStatus)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); + } + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeString(first_name); + stream.writeString(last_name); + stream.writeInt64(access_hash); + photo.serializeToStream(stream); + status.serializeToStream(stream); + } + } + + public static class TL_userRequest_old extends TL_userRequest { + public static int constructor = 0x22e8ceb0; + + + public void readParams(AbsSerializedData stream) { + id = stream.readInt32(); + first_name = stream.readString(); + last_name = stream.readString(); + access_hash = stream.readInt64(); + phone = stream.readString(); + photo = (UserProfilePhoto)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); + status = (UserStatus)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); + } + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeString(first_name); + stream.writeString(last_name); + stream.writeInt64(access_hash); + stream.writeString(phone); + photo.serializeToStream(stream); + status.serializeToStream(stream); + } + } + + public static class TL_userContact_old extends TL_userContact { + public static int constructor = 0xf2fb8319; + + + public void readParams(AbsSerializedData stream) { + id = stream.readInt32(); + first_name = stream.readString(); + last_name = stream.readString(); + access_hash = stream.readInt64(); + phone = stream.readString(); + photo = (UserProfilePhoto)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); + status = (UserStatus)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); + } + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeString(first_name); + stream.writeString(last_name); + stream.writeInt64(access_hash); + stream.writeString(phone); + photo.serializeToStream(stream); + status.serializeToStream(stream); + } + } + + public static class TL_userSelf_old extends TL_userSelf { + public static int constructor = 0x720535ec; + + + public void readParams(AbsSerializedData stream) { + id = stream.readInt32(); + first_name = stream.readString(); + last_name = stream.readString(); + phone = stream.readString(); + photo = (UserProfilePhoto)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); + status = (UserStatus)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); + inactive = stream.readBool(); + } + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeString(first_name); + stream.writeString(last_name); + stream.writeString(phone); + photo.serializeToStream(stream); + status.serializeToStream(stream); + stream.writeBool(inactive); + } + } + public static class TL_set_client_DH_params extends TLObject { public static int constructor = 0xf5045f1f; @@ -9129,6 +9342,7 @@ public class TLRPC { public int id; public String first_name; public String last_name; + public String username; public long access_hash; public String phone; public UserProfilePhoto photo; @@ -9629,8 +9843,8 @@ public class TLRPC { } } - public static class invokeWithLayer17 extends TLObject { - public static int constructor = 0x50858a19; + public static class invokeWithLayer18 extends TLObject { + public static int constructor = 0x1c900537; public TLObject query; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivitySearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivitySearchAdapter.java index c6fc1baf..ec2e602b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivitySearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivitySearchAdapter.java @@ -9,10 +9,17 @@ package org.telegram.ui.Adapters; import android.content.Context; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.TextView; import org.telegram.android.AndroidUtilities; +import org.telegram.android.LocaleController; +import org.telegram.messenger.ConnectionsManager; +import org.telegram.messenger.R; +import org.telegram.messenger.RPCRequest; +import org.telegram.messenger.TLObject; import org.telegram.messenger.TLRPC; import org.telegram.android.ContactsController; import org.telegram.messenger.FileLog; @@ -32,6 +39,9 @@ public class ContactsActivitySearchAdapter extends BaseFragmentAdapter { private ArrayList searchResult; private ArrayList searchResultNames; private Timer searchTimer; + private ArrayList globalSearch; + private long reqId = 0; + private int lastReqId; public ContactsActivitySearchAdapter(Context context, HashMap arg1) { mContext = context; @@ -42,6 +52,8 @@ public class ContactsActivitySearchAdapter extends BaseFragmentAdapter { if (query == null) { searchResult = null; searchResultNames = null; + globalSearch = null; + queryServerSearch(null); notifyDataSetChanged(); } else { try { @@ -63,14 +75,50 @@ public class ContactsActivitySearchAdapter extends BaseFragmentAdapter { } processSearch(query); } - }, 100, 300); + }, 200, 300); } } + private void queryServerSearch(String query) { + if (query == null || query.length() < 5) { + if (reqId != 0) { + ConnectionsManager.getInstance().cancelRpc(reqId, true); + reqId = 0; + } + globalSearch = null; + lastReqId = 0; + notifyDataSetChanged(); + return; + } + TLRPC.TL_contacts_search req = new TLRPC.TL_contacts_search(); + req.q = query; + req.limit = 50; + final int currentReqId = ++lastReqId; + reqId = ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + if (currentReqId == lastReqId) { + if (error == null) { + TLRPC.TL_contacts_found res = (TLRPC.TL_contacts_found) response; + globalSearch = res.users; + notifyDataSetChanged(); + } + } + reqId = 0; + } + }); + } + }, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors); + } + private void processSearch(final String query) { AndroidUtilities.RunOnUIThread(new Runnable() { @Override public void run() { + queryServerSearch(query); final ArrayList contactsCopy = new ArrayList(); contactsCopy.addAll(ContactsController.getInstance().contacts); Utilities.searchQueue.postRunnable(new Runnable() { @@ -117,28 +165,43 @@ public class ContactsActivitySearchAdapter extends BaseFragmentAdapter { @Override public boolean areAllItemsEnabled() { - return true; + return false; } @Override public boolean isEnabled(int i) { - return true; + return i != (searchResult == null ? 0 : searchResult.size()); } @Override public int getCount() { - if (searchResult == null) { - return 0; + int count = searchResult == null ? 0 : searchResult.size(); + int globalCount = globalSearch == null ? 0 : globalSearch.size(); + if (globalCount != 0) { + count += globalCount + 1; } - return searchResult.size(); + return count; + } + + public boolean isGlobalSearch(int i) { + int localCount = searchResult == null ? 0 : searchResult.size(); + int globalCount = globalSearch == null ? 0 : globalSearch.size(); + if (i >= 0 && i < localCount) { + return false; + } else if (i > localCount && i <= globalCount + localCount) { + return true; + } + return false; } @Override public TLRPC.User getItem(int i) { - if (searchResult != null) { - if (i >= 0 && i < searchResult.size()) { - return searchResult.get(i); - } + int localCount = searchResult == null ? 0 : searchResult.size(); + int globalCount = globalSearch == null ? 0 : globalSearch.size(); + if (i >= 0 && i < localCount) { + return searchResult.get(i); + } else if (i > localCount && i <= globalCount + localCount) { + return globalSearch.get(i - localCount - 1); } return null; } @@ -155,24 +218,30 @@ public class ContactsActivitySearchAdapter extends BaseFragmentAdapter { @Override public View getView(int i, View view, ViewGroup viewGroup) { - if (view == null) { - view = new ChatOrUserCell(mContext); - ((ChatOrUserCell)view).usePadding = false; - } + if (i == (searchResult == null ? 0 : searchResult.size())) { + if (view == null) { + LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + view = li.inflate(R.layout.settings_section_layout, viewGroup, false); + TextView textView = (TextView)view.findViewById(R.id.settings_section_text); + textView.setText(LocaleController.getString("GlobalSearch", R.string.GlobalSearch)); + } + } else { + if (view == null) { + view = new ChatOrUserCell(mContext); + ((ChatOrUserCell) view).usePadding = false; + } - ((ChatOrUserCell) view).useSeparator = i != searchResult.size() - 1; + ((ChatOrUserCell) view).useSeparator = (i != getCount() - 1 && i != searchResult.size() - 1); + TLRPC.User user = getItem(i); + if (user != null) { + ((ChatOrUserCell) view).setData(user, null, null, i < searchResult.size() ? searchResultNames.get(i) : null, i > searchResult.size() ? "@" + user.username : null); - Object obj = searchResult.get(i); - TLRPC.User user = MessagesController.getInstance().getUser(((TLRPC.User)obj).id); - - if (user != null) { - ((ChatOrUserCell)view).setData(user, null, null, searchResultNames.get(i), null); - - if (ignoreUsers != null) { - if (ignoreUsers.containsKey(user.id)) { - ((ChatOrUserCell)view).drawAlpha = 0.5f; - } else { - ((ChatOrUserCell)view).drawAlpha = 1.0f; + if (ignoreUsers != null) { + if (ignoreUsers.containsKey(user.id)) { + ((ChatOrUserCell) view).drawAlpha = 0.5f; + } else { + ((ChatOrUserCell) view).drawAlpha = 1.0f; + } } } } @@ -181,16 +250,19 @@ public class ContactsActivitySearchAdapter extends BaseFragmentAdapter { @Override public int getItemViewType(int i) { + if (i == (searchResult == null ? 0 : searchResult.size())) { + return 1; + } return 0; } @Override public int getViewTypeCount() { - return 1; + return 2; } @Override public boolean isEmpty() { - return searchResult == null || searchResult.size() == 0; + return (searchResult == null || searchResult.size() == 0) && (globalSearch == null || globalSearch.isEmpty()); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java index b6041c68..34e8e74a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java @@ -36,6 +36,7 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega private static TextPaint timePaint; private ImageReceiver avatarImage; + private boolean needAvatarImage = false; private SeekBar seekBar; private ProgressView progressView; private int seekBarX; @@ -117,7 +118,7 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega buttonPressed = true; invalidate(); result = true; - } else if (avatarImage.isInsideImage(x, y)) { + } else if (needAvatarImage && avatarImage.isInsideImage(x, y)) { avatarPressed = true; result = true; } @@ -317,11 +318,19 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega timeX = AndroidUtilities.dp(80); } } - avatarImage.setImageCoords(x, AndroidUtilities.dp(9), AndroidUtilities.dp(50), AndroidUtilities.dp(50)); + int diff = 0; + if (needAvatarImage) { + avatarImage.setImageCoords(x, AndroidUtilities.dp(9), AndroidUtilities.dp(50), AndroidUtilities.dp(50)); + } else { + diff = AndroidUtilities.dp(56); + seekBarX -= diff; + buttonX -= diff; + timeX -= diff; + } - seekBar.width = backgroundWidth - AndroidUtilities.dp(112); + seekBar.width = backgroundWidth - AndroidUtilities.dp(112) + diff; seekBar.height = AndroidUtilities.dp(30); - progressView.width = backgroundWidth - AndroidUtilities.dp(136); + progressView.width = backgroundWidth - AndroidUtilities.dp(136) + diff; progressView.height = AndroidUtilities.dp(30); seekBarY = AndroidUtilities.dp(13); buttonY = AndroidUtilities.dp(10); @@ -348,14 +357,18 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega if (uid == 0) { uid = messageObject.messageOwner.from_id; } + needAvatarImage = !(messageObject.messageOwner.to_id != null && messageObject.messageOwner.to_id.chat_id != 0 && !messageObject.isOut() && messageObject.messageOwner.media.audio.user_id == messageObject.messageOwner.from_id); audioUser = MessagesController.getInstance().getUser(uid); - if (audioUser != null) { - if (audioUser.photo != null) { - currentPhoto = audioUser.photo.photo_small; + + if (needAvatarImage) { + if (audioUser != null) { + if (audioUser.photo != null) { + currentPhoto = audioUser.photo.photo_small; + } + avatarImage.setImage(currentPhoto, "50_50", getResources().getDrawable(AndroidUtilities.getUserAvatarForId(uid)), false); + } else { + avatarImage.setImage(null, "50_50", getResources().getDrawable(AndroidUtilities.getUserAvatarForId(uid)), false); } - avatarImage.setImage(currentPhoto, "50_50", getResources().getDrawable(AndroidUtilities.getUserAvatarForId(uid)), false); - } else { - avatarImage.setImage(null, "50_50", getResources().getDrawable(AndroidUtilities.getUserAvatarForId(uid)), false); } if (messageObject.isOut()) { @@ -379,7 +392,9 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega return; } - avatarImage.draw(canvas, avatarImage.getImageX(), avatarImage.getImageY(), avatarImage.getImageHeight(), avatarImage.getImageHeight()); + if (needAvatarImage) { + avatarImage.draw(canvas, avatarImage.getImageX(), avatarImage.getImageY(), avatarImage.getImageHeight(), avatarImage.getImageHeight()); + } canvas.save(); if (buttonState == 0 || buttonState == 1) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java index 7b0f14d2..1621d812 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java @@ -10,7 +10,6 @@ package org.telegram.ui.Cells; import android.content.Context; import android.graphics.Canvas; -import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.text.Layout; import android.text.StaticLayout; @@ -39,8 +38,8 @@ public class ChatContactCell extends ChatBaseCell { private static TextPaint namePaint; private static TextPaint phonePaint; - private static Drawable addContactDrawable; - private static Paint linePaint; + private static Drawable addContactDrawableIn; + private static Drawable addContactDrawableOut; private ImageReceiver avatarImage; @@ -67,10 +66,8 @@ public class ChatContactCell extends ChatBaseCell { phonePaint.setTextSize(AndroidUtilities.dp(15)); phonePaint.setColor(0xff000000); - addContactDrawable = getResources().getDrawable(R.drawable.ic_ab_add_member); - - linePaint = new Paint(); - linePaint.setStrokeWidth(AndroidUtilities.dp(1)); + addContactDrawableIn = getResources().getDrawable(R.drawable.addcontact_blue); + addContactDrawableOut = getResources().getDrawable(R.drawable.addcontact_green); } avatarImage = new ImageReceiver(this); } @@ -85,6 +82,12 @@ public class ChatContactCell extends ChatBaseCell { return false; } + int uid = currentMessageObject.messageOwner.media.user_id; + boolean newDrawAdd = contactUser != null && uid != UserConfig.getClientUserId() && ContactsController.getInstance().contactsDict.get(uid) == null; + if (newDrawAdd != drawAddButton) { + return true; + } + contactUser = MessagesController.getInstance().getUser(currentMessageObject.messageOwner.media.user_id); TLRPC.FileLocation newPhoto = null; @@ -103,10 +106,10 @@ public class ChatContactCell extends ChatBaseCell { boolean result = false; int side = AndroidUtilities.dp(36); if (event.getAction() == MotionEvent.ACTION_DOWN) { - if (x >= avatarImage.getImageX() && x <= avatarImage.getImageX() + namesWidth && y >= avatarImage.getImageY() && y <= avatarImage.getImageY() + avatarImage.getImageHeight()) { + if (x >= avatarImage.getImageX() && x <= avatarImage.getImageX() + namesWidth + AndroidUtilities.dp(42) && y >= avatarImage.getImageY() && y <= avatarImage.getImageY() + avatarImage.getImageHeight()) { avatarPressed = true; result = true; - } else if (x >= avatarImage.getImageX() - AndroidUtilities.dp(44) && y >= AndroidUtilities.dp(20) && x <= avatarImage.getImageX() - AndroidUtilities.dp(10) && y <= AndroidUtilities.dp(52)) { + } else if (x >= avatarImage.getImageX() + namesWidth + AndroidUtilities.dp(52) && y >= AndroidUtilities.dp(13) && x <= avatarImage.getImageX() + namesWidth + AndroidUtilities.dp(92) && y <= AndroidUtilities.dp(52)) { buttonPressed = true; result = true; } @@ -133,7 +136,7 @@ public class ChatContactCell extends ChatBaseCell { } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { avatarPressed = false; } else if (event.getAction() == MotionEvent.ACTION_MOVE) { - if (!avatarImage.isInsideImage(x, y)) { + if (!(x >= avatarImage.getImageX() && x <= avatarImage.getImageX() + namesWidth + AndroidUtilities.dp(42) && y >= avatarImage.getImageY() && y <= avatarImage.getImageY() + avatarImage.getImageHeight())) { avatarPressed = false; } } @@ -147,7 +150,7 @@ public class ChatContactCell extends ChatBaseCell { } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { buttonPressed = false; } else if (event.getAction() == MotionEvent.ACTION_MOVE) { - if (!(x >= avatarImage.getImageX() - AndroidUtilities.dp(44) && y >= AndroidUtilities.dp(20) && x <= avatarImage.getImageX() - AndroidUtilities.dp(10) && y <= AndroidUtilities.dp(52))) { + if (!(x >= avatarImage.getImageX() + namesWidth + AndroidUtilities.dp(52) && y >= AndroidUtilities.dp(13) && x <= avatarImage.getImageX() + namesWidth + AndroidUtilities.dp(92) && y <= AndroidUtilities.dp(52))) { buttonPressed = false; } } @@ -175,7 +178,7 @@ public class ChatContactCell extends ChatBaseCell { } else { maxWidth = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.7f); } - maxWidth -= AndroidUtilities.dp(58 + (drawAddButton ? 52 : 0)); + maxWidth -= AndroidUtilities.dp(58 + (drawAddButton ? 42 : 0)); if (contactUser != null) { if (contactUser.photo != null) { @@ -216,7 +219,7 @@ public class ChatContactCell extends ChatBaseCell { } namesWidth = Math.max(nameWidth, phoneWidth); - backgroundWidth = AndroidUtilities.dp(75 + (drawAddButton ? 52 : 0)) + namesWidth; + backgroundWidth = AndroidUtilities.dp(77 + (drawAddButton ? 42 : 0)) + namesWidth; super.setMessageObject(messageObject); } @@ -238,15 +241,15 @@ public class ChatContactCell extends ChatBaseCell { int x; if (currentMessageObject.isOut()) { - x = layoutWidth - backgroundWidth + AndroidUtilities.dp(6); + x = layoutWidth - backgroundWidth + AndroidUtilities.dp(8); } else { if (isChat) { - x = AndroidUtilities.dp(67); + x = AndroidUtilities.dp(69); } else { - x = AndroidUtilities.dp(14); + x = AndroidUtilities.dp(16); } } - avatarImage.setImageCoords(x + (drawAddButton ? AndroidUtilities.dp(52) : 0), AndroidUtilities.dp(7), AndroidUtilities.dp(42), AndroidUtilities.dp(42)); + avatarImage.setImageCoords(x, AndroidUtilities.dp(9), AndroidUtilities.dp(42), AndroidUtilities.dp(42)); } @Override @@ -261,27 +264,26 @@ public class ChatContactCell extends ChatBaseCell { if (nameLayout != null) { canvas.save(); - canvas.translate(avatarImage.getImageX() + avatarImage.getImageWidth() + AndroidUtilities.dp(9), AndroidUtilities.dp(8)); + canvas.translate(avatarImage.getImageX() + avatarImage.getImageWidth() + AndroidUtilities.dp(9), AndroidUtilities.dp(10)); namePaint.setColor(AndroidUtilities.getColorForId(currentMessageObject.messageOwner.media.user_id)); nameLayout.draw(canvas); canvas.restore(); } if (phoneLayout != null) { canvas.save(); - canvas.translate(avatarImage.getImageX() + avatarImage.getImageWidth() + AndroidUtilities.dp(9), AndroidUtilities.dp(29)); + canvas.translate(avatarImage.getImageX() + avatarImage.getImageWidth() + AndroidUtilities.dp(9), AndroidUtilities.dp(31)); phoneLayout.draw(canvas); canvas.restore(); } if (drawAddButton) { + Drawable addContactDrawable; if (currentMessageObject.isOut()) { - linePaint.setColor(0x9670b15c); + addContactDrawable = addContactDrawableOut; } else { - linePaint.setColor(0xffe8e8e8); + addContactDrawable = addContactDrawableIn; } - canvas.drawLine(avatarImage.getImageX() - AndroidUtilities.dp(4), avatarImage.getImageY(), avatarImage.getImageX() - AndroidUtilities.dp(4), AndroidUtilities.dp(62), linePaint); - - setDrawableBounds(addContactDrawable, avatarImage.getImageX() - AndroidUtilities.dp(44), AndroidUtilities.dp(20)); + setDrawableBounds(addContactDrawable, avatarImage.getImageX() + namesWidth + AndroidUtilities.dp(78), AndroidUtilities.dp(13)); addContactDrawable.draw(canvas); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java index d530fdc8..9bfd611b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java @@ -30,6 +30,7 @@ import android.widget.TextView; import org.telegram.android.AndroidUtilities; import org.telegram.android.LocaleController; +import org.telegram.android.MessagesStorage; import org.telegram.messenger.TLObject; import org.telegram.messenger.TLRPC; import org.telegram.messenger.ConnectionsManager; @@ -221,6 +222,12 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter if (user == null || user.id == UserConfig.getClientUserId()) { return; } + if (searchListViewAdapter.isGlobalSearch(i)) { + ArrayList users = new ArrayList(); + users.add(user); + MessagesController.getInstance().putUsers(users, false); + MessagesStorage.getInstance().putUsersAndChats(users, null, false, true); + } if (returnAsResult) { if (ignoreUsers != null && ignoreUsers.containsKey(user.id)) { return; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java index ce0c21d9..daa9f6de 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java @@ -73,6 +73,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter private int profileRow; private int numberSectionRow; private int numberRow; + private int usernameRow; private int settingsSectionRow; private int textSizeRow; private int enableAnimationsRow; @@ -179,6 +180,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter profileRow = rowCount++; numberSectionRow = rowCount++; numberRow = rowCount++; + usernameRow = rowCount++; settingsSectionRow = rowCount++; enableAnimationsRow = rowCount++; languageRow = rowCount++; @@ -208,12 +210,15 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter logoutRow = rowCount++; versionRow = rowCount++; + MessagesController.getInstance().loadFullUser(UserConfig.getCurrentUser(), classGuid); + return true; } @Override public void onFragmentDestroy() { super.onFragmentDestroy(); + MessagesController.getInstance().cancelLoadFullUser(UserConfig.getClientUserId()); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.updateInterfaces); avatarUpdater.clear(); } @@ -477,6 +482,8 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter }); builder.setNegativeButton(LocaleController.getString("OK", R.string.OK), null); showAlertDialog(builder); + } else if (i == usernameRow) { + presentFragment(new SettingsChangeUsernameActivity()); } } }); @@ -709,7 +716,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter public boolean isEnabled(int i) { return i == textSizeRow || i == enableAnimationsRow || i == blockedRow || i == notificationRow || i == backgroundRow || i == askQuestionRow || i == sendLogsRow || i == sendByEnterRow || i == terminateSessionsRow || i == wifiDownloadRow || - i == mobileDownloadRow || i == clearLogsRow || i == roamingDownloadRow || i == languageRow || + i == mobileDownloadRow || i == clearLogsRow || i == roamingDownloadRow || i == languageRow || i == usernameRow || i == switchBackendButtonRow || i == telegramFaqRow || i == contactsSortRow || i == contactsReimportRow || i == saveToGalleryRow; } @@ -829,7 +836,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter } TextView textView = (TextView)view.findViewById(R.id.settings_section_text); if (i == numberSectionRow) { - textView.setText(LocaleController.getString("YourPhoneNumber", R.string.YourPhoneNumber)); + textView.setText(LocaleController.getString("Info", R.string.Info)); } else if (i == settingsSectionRow) { textView.setText(LocaleController.getString("SETTINGS", R.string.SETTINGS)); } else if (i == supportSectionRow) { @@ -848,15 +855,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter } TextView textView = (TextView)view.findViewById(R.id.settings_row_text); View divider = view.findViewById(R.id.settings_row_divider); - if (i == numberRow) { - TLRPC.User user = UserConfig.getCurrentUser(); - if (user != null && user.phone != null && user.phone.length() != 0) { - textView.setText(PhoneFormat.getInstance().format("+" + user.phone)); - } else { - textView.setText(LocaleController.getString("Unknown", R.string.Unknown)); - } - divider.setVisibility(View.INVISIBLE); - } else if (i == notificationRow) { + if (i == notificationRow) { textView.setText(LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds)); divider.setVisibility(View.VISIBLE); } else if (i == blockedRow) { @@ -966,7 +965,16 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter TextView textView = (TextView)view.findViewById(R.id.settings_row_text); TextView detailTextView = (TextView)view.findViewById(R.id.settings_row_text_detail); View divider = view.findViewById(R.id.settings_row_divider); - if (i == textSizeRow) { + if (i == numberRow) { + TLRPC.User user = UserConfig.getCurrentUser(); + textView.setText(LocaleController.getString("Phone", R.string.Phone)); + if (user != null && user.phone != null && user.phone.length() != 0) { + detailTextView.setText(PhoneFormat.getInstance().format("+" + user.phone)); + } else { + detailTextView.setText(LocaleController.getString("Unknown", R.string.Unknown)); + } + divider.setVisibility(View.VISIBLE); + } else if (i == textSizeRow) { SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); int size = preferences.getInt("fons_size", AndroidUtilities.isTablet() ? 18 : 16); detailTextView.setText(String.format("%d", size)); @@ -988,6 +996,15 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter } else if (sort == 2) { detailTextView.setText(LocaleController.getString("LastName", R.string.SortLastName)); } + } else if (i == usernameRow) { + TLRPC.User user = UserConfig.getCurrentUser(); + textView.setText(LocaleController.getString("Username", R.string.Username)); + if (user != null && user.username != null && user.username.length() != 0) { + detailTextView.setText("@" + user.username); + } else { + detailTextView.setText("-"); + } + divider.setVisibility(View.INVISIBLE); } } else if (type == 6) { if (view == null) { @@ -1061,11 +1078,11 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter return 0; } else if (i == numberSectionRow || i == settingsSectionRow || i == supportSectionRow || i == messagesSectionRow || i == mediaDownloadSection || i == contactsSectionRow) { return 1; - } else if (i == textSizeRow || i == languageRow || i == contactsSortRow) { + } else if (i == textSizeRow || i == languageRow || i == contactsSortRow || i == numberRow || i == usernameRow) { return 5; } else if (i == enableAnimationsRow || i == sendByEnterRow || i == saveToGalleryRow) { return 3; - } else if (i == numberRow || i == notificationRow || i == blockedRow || i == backgroundRow || i == askQuestionRow || i == sendLogsRow || i == terminateSessionsRow || i == clearLogsRow || i == switchBackendButtonRow || i == telegramFaqRow || i == contactsReimportRow) { + } else if (i == notificationRow || i == blockedRow || i == backgroundRow || i == askQuestionRow || i == sendLogsRow || i == terminateSessionsRow || i == clearLogsRow || i == switchBackendButtonRow || i == telegramFaqRow || i == contactsReimportRow) { return 2; } else if (i == logoutRow) { return 4; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeNameActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeNameActivity.java index 2806c050..86557b08 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeNameActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeNameActivity.java @@ -125,12 +125,13 @@ public class SettingsChangeNameActivity extends BaseFragment { } private void saveName() { - TLRPC.TL_account_updateProfile req = new TLRPC.TL_account_updateProfile(); - if (UserConfig.getCurrentUser() == null || lastNameField.getText() == null || firstNameField.getText() == null) { + TLRPC.User currentUser = UserConfig.getCurrentUser(); + if (currentUser == null || lastNameField.getText() == null || firstNameField.getText() == null) { return; } - UserConfig.getCurrentUser().first_name = req.first_name = firstNameField.getText().toString(); - UserConfig.getCurrentUser().last_name = req.last_name = lastNameField.getText().toString(); + TLRPC.TL_account_updateProfile req = new TLRPC.TL_account_updateProfile(); + currentUser.first_name = req.first_name = firstNameField.getText().toString(); + currentUser.last_name = req.last_name = lastNameField.getText().toString(); TLRPC.User user = MessagesController.getInstance().getUser(UserConfig.getClientUserId()); if (user != null) { user.first_name = req.first_name; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java new file mode 100644 index 00000000..ca1e855b --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java @@ -0,0 +1,216 @@ +/* + * This is the source code of Telegram for Android v. 1.7.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2014. + */ + +package org.telegram.ui; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; + +import org.telegram.android.AndroidUtilities; +import org.telegram.android.LocaleController; +import org.telegram.android.MessagesController; +import org.telegram.android.MessagesStorage; +import org.telegram.android.NotificationCenter; +import org.telegram.messenger.ConnectionsManager; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.R; +import org.telegram.messenger.RPCRequest; +import org.telegram.messenger.TLObject; +import org.telegram.messenger.TLRPC; +import org.telegram.messenger.UserConfig; +import org.telegram.ui.Views.ActionBar.BaseFragment; + +import java.util.ArrayList; + +public class SettingsChangeUsernameActivity extends BaseFragment { + private EditText firstNameField; + private View headerLabelView; + private View doneButton; + + @Override + public View createView(LayoutInflater inflater, ViewGroup container) { + if (fragmentView == null) { + actionBarLayer.setCustomView(R.layout.settings_do_action_layout); + Button cancelButton = (Button)actionBarLayer.findViewById(R.id.cancel_button); + cancelButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + finishFragment(); + } + }); + doneButton = actionBarLayer.findViewById(R.id.done_button); + doneButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (firstNameField.getText().length() != 0) { + saveName(); + } + } + }); + + cancelButton.setText(LocaleController.getString("Cancel", R.string.Cancel).toUpperCase()); + TextView textView = (TextView)doneButton.findViewById(R.id.done_button_text); + textView.setText(LocaleController.getString("Done", R.string.Done).toUpperCase()); + + fragmentView = inflater.inflate(R.layout.chat_profile_change_name_layout, container, false); + + TLRPC.User user = MessagesController.getInstance().getUser(UserConfig.getClientUserId()); + if (user == null) { + user = UserConfig.getCurrentUser(); + } + + firstNameField = (EditText)fragmentView.findViewById(R.id.first_name_field); + firstNameField.setOnEditorActionListener(new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { + if (i == EditorInfo.IME_ACTION_DONE) { + doneButton.performClick(); + return true; + } + return false; + } + }); + + if (user != null && user.username != null && user.username.length() > 0) { + firstNameField.setText(user.username); + firstNameField.setSelection(firstNameField.length()); + } + + TextView headerLabel = (TextView)fragmentView.findViewById(R.id.settings_section_text); + headerLabel.setText(LocaleController.getString("Username", R.string.Username).toUpperCase()); + } else { + ViewGroup parent = (ViewGroup)fragmentView.getParent(); + if (parent != null) { + parent.removeView(fragmentView); + } + } + return fragmentView; + } + + @Override + public void onResume() { + super.onResume(); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + boolean animations = preferences.getBoolean("view_animations", true); + if (!animations) { + firstNameField.requestFocus(); + AndroidUtilities.showKeyboard(firstNameField); + } + } + + private void showErrorAlert(String error) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + if (error.equals("USERNAME_INVALID")) { + builder.setMessage(LocaleController.getString("UsernameInvalid", R.string.UsernameInvalid)); + } else if (error.equals("USERNAME_OCCUPIED")) { + builder.setMessage(LocaleController.getString("UsernameInUse", R.string.UsernameInUse)); + } else { + builder.setMessage(error); + } + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + showAlertDialog(builder); + } + + private void saveName() { + TLRPC.User user = UserConfig.getCurrentUser(); + if (getParentActivity() == null || user == null) { + return; + } + String currentName = user.username; + if (currentName == null) { + currentName = ""; + } + String newName = firstNameField.getText().toString(); + if (currentName.equals(newName)) { + finishFragment(); + return; + } + if (newName.length() > 32 || newName.length() > 0 && newName.length() < 5) { + showErrorAlert("USERNAME_INVALID"); + return; + } + + final ProgressDialog progressDialog = new ProgressDialog(getParentActivity()); + progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); + progressDialog.setCanceledOnTouchOutside(false); + progressDialog.setCancelable(false); + + TLRPC.TL_account_updateUsername req = new TLRPC.TL_account_updateUsername(); + req.username = newName; + + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_NAME); + final long reqId = ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() { + @Override + public void run(TLObject response, final TLRPC.TL_error error) { + if (error == null) { + final TLRPC.User user = (TLRPC.User)response; + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + ArrayList users = new ArrayList(); + users.add(user); + MessagesController.getInstance().putUsers(users, false); + MessagesStorage.getInstance().putUsersAndChats(users, null, false, true); + UserConfig.saveConfig(true); + finishFragment(); + } + }); + } else { + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + showErrorAlert(error.text); + } + }); + } + } + }, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors); + ConnectionsManager.getInstance().bindRequestToGuid(reqId, classGuid); + + progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + ConnectionsManager.getInstance().cancelRpc(reqId, true); + try { + dialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + progressDialog.show(); + } + + @Override + public void onOpenAnimationEnd() { + firstNameField.requestFocus(); + AndroidUtilities.showKeyboard(firstNameField); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java index 0d41355f..84c53c1a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java @@ -63,6 +63,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen private int avatarRow; private int phoneSectionRow; private int phoneRow; + private int usernameRow; private int settingsSectionRow; private int settingsTimerRow; private int settingsKeyRow; @@ -93,6 +94,9 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen NotificationCenter.getInstance().addObserver(this, NotificationCenter.encryptedChatUpdated); NotificationCenter.getInstance().addObserver(this, NotificationCenter.blockedUsersDidLoaded); userBlocked = MessagesController.getInstance().blockedUsers.contains(user_id); + + MessagesController.getInstance().loadFullUser(MessagesController.getInstance().getUser(user_id), classGuid); + return true; } @@ -105,6 +109,8 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen NotificationCenter.getInstance().removeObserver(this, NotificationCenter.encryptedChatCreated); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.encryptedChatUpdated); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.blockedUsersDidLoaded); + + MessagesController.getInstance().cancelLoadFullUser(user_id); } private void updateRowsIds() { @@ -112,6 +118,12 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen avatarRow = rowCount++; phoneSectionRow = rowCount++; phoneRow = rowCount++; + TLRPC.User user = MessagesController.getInstance().getUser(user_id); + if (user != null && user.username != null && user.username.length() > 0) { + usernameRow = rowCount++; + } else { + usernameRow = -1; + } settingsSectionRow = rowCount++; if (currentEncryptedChat instanceof TLRPC.TL_encryptedChat) { settingsTimerRow = rowCount++; @@ -281,6 +293,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen if (id == NotificationCenter.updateInterfaces) { int mask = (Integer)args[0]; if ((mask & MessagesController.UPDATE_MASK_AVATAR) != 0 || (mask & MessagesController.UPDATE_MASK_NAME) != 0) { + updateRowsIds(); if (listView != null) { listView.invalidateViews(); } @@ -531,7 +544,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen } TextView textView = (TextView)view.findViewById(R.id.settings_section_text); if (i == phoneSectionRow) { - textView.setText(LocaleController.getString("PHONE", R.string.PHONE)); + textView.setText(LocaleController.getString("Info", R.string.Info)); } else if (i == settingsSectionRow) { textView.setText(LocaleController.getString("SETTINGS", R.string.SETTINGS)); } else if (i == sharedMediaSectionRow) { @@ -610,7 +623,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen } else { textView.setText(LocaleController.getString("Unknown", R.string.Unknown)); } - divider.setVisibility(View.INVISIBLE); + divider.setVisibility(usernameRow != -1 ? View.VISIBLE : View.INVISIBLE); detailTextView.setText(LocaleController.getString("PhoneMobile", R.string.PhoneMobile)); } } else if (type == 3) { @@ -639,6 +652,15 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen } else { detailTextView.setText(AndroidUtilities.formatTTLString(encryptedChat.ttl)); } + } else if (i == usernameRow) { + TLRPC.User user = MessagesController.getInstance().getUser(user_id); + textView.setText(LocaleController.getString("Username", R.string.Username)); + if (user != null && user.username != null && user.username.length() != 0) { + detailTextView.setText("@" + user.username); + } else { + detailTextView.setText("-"); + } + divider.setVisibility(View.INVISIBLE); } } else if (type == 4) { if (view == null) { @@ -675,7 +697,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen return 1; } else if (i == phoneRow) { return 2; - } else if (i == sharedMediaRow || i == settingsTimerRow) { + } else if (i == sharedMediaRow || i == settingsTimerRow || i == usernameRow) { return 3; } else if (i == settingsKeyRow) { return 4; diff --git a/TMessagesProj/src/main/res/drawable-hdpi/addcontact_blue.png b/TMessagesProj/src/main/res/drawable-hdpi/addcontact_blue.png new file mode 100755 index 0000000000000000000000000000000000000000..a90b6ce9c694f0968ee270a64972c4a3ec2dbb4f GIT binary patch literal 966 zcmaJ=&ui0A91okwob)vOF+qG}2oBaHuWi!i(KyN%ntv?)f7&%+qR%u9FV!TOsC34ryaxcvcrTu;uLD`h<%dH_f}v z7Hyf=kxe|oN-#p~1&qyc#pO7#>@7?|8+Tn_{IzKsoC85Om{S*8bJa`e@ZN7AE=fN71ydQi%pYQj5zn^zdE^Q?iE-f$& zlhC)d3LVeK-&A@ zaSK}5<;)nvMXpcT43pW6eADV60vf30cq;qz{YMr!w#x2EhG6)4)ONN90jds4HEYnZ z6r0_=0WuM!0xlvZh}=CdgptY)bs?R{+dK<~5YkcElcefK8RT(*fW)mOEkP84EOTO7 zl4bEaNC{$!7w9V|#Wa*;m|6#;ho#X1y9p~=aTJTLRJKis4|%@V>v6p`4hJn>R1_uF zNTre#kqrADF{7jxu8b8l6k37f69;=BRx}&9OH`I-dU6EUpU8UQs7$nAd}R8($O-Y0 z#z4dPKh$+6=#W&IHCN(LKFkNmBsi#Hyf?05xs3@9+t>&B zstm5}IG&Ar;pz}?7*O{@VtN+RHI=0boa5L~k#ieatsqO%h9ZiEv?3R?nvfL>TDDLW zq}-URVXNyRkBqtYDR+G;H@1T7)5sbMoO{SF2G|9|BSU9;F6pUyBd$F?7ilV&r^)bf zWB+ROc#FCxo=$8_7Zc+nkGegewthB$G)u1p)U|9a`rdf7yY%_y+|lDNP3^FL?%n0Q zxHy~m^!oXW{mQa1vv_>`2zRyU09zb@uA*)WNs-X6c2J_BMCt F!5{F@E2RJc literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/ic_ab_add_member.png b/TMessagesProj/src/main/res/drawable-hdpi/ic_ab_add_member.png deleted file mode 100644 index cd5eaa0afc739354aebd6c7f6fa379db1055d1a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1700 zcmbVNc~BE)6kkz9@jyjU3XV&ZqsS(^*<70v)%@fwTNqA0D_Qi=!`sfs~|0n{qYpbnrmgB%4FyFsx1!|{*q%7)){Ct00gcy8*sUXpg~Izp82&pjshf z#B!yu)DTLj)T>gA#JZHo7#ye7R(kL*LG!h_}$%W)F!U6dh6X7Bp0TKYRVFYEtC<{R$ge`2Q6HjB-MXbs3@(Nnk?(wmk}SP&B? zxlwJP)TAD?Tf}8#5+!2LOy7l|Gf1WH4eL$giK0`+GUEmo!h~5mojtBGZ4(tu{7d75 z+NKzbfnY@wCNjw=r|XfhbOKE0?&FT^iZmPH=SDSM6kIDN|Lf=)B4?=JIZB*W9*2IJ9!kky_7!Dd}D=OFA4Mq$N;&bzk7qR0)M5h1 zl{fr>hRkLv=wQUrKPx70J`x5rwKjXE7tS3y+^$M5&2qL5?3(hV0XA>J7yp{w=UbR} z``o@p%lZ8kt#wW{?pymCtY4;iAx`t!SGOK0Naap#%I5n1lySu4@rklLbitLrveH6T zL6k?i5?t7JZ@y;I$sEU=3b#DITizu%TVvc6rDoE(+6ylR&t_j;cA=7UcVKYG%%q!U zsQOy!VO#S^prK_hIQ_Y*)0)Q27;btksovGqyR%Kay?Mi#zADki!jU$gg7Vf<*T(vs zivdOHO%Vq>ftj<~pZcqsd*f|j_sgJ6VY6~mh3mtimv=X|O)Gj#cI;h$Y0H6t(#cTj zxzC0wI|8-VdBa=23P?k(J%UGWEyI2hf8^vQWany+zG-&1%%}<8cG?}jX9=JEch$-I zQGv@qbe%TU+xzB|<$~G#l8*UY&&PO+Rm&k3hvIYZ<^(qJMDV^!BbUhzOr{I~k2l}&F;iqNp)+uMGZ-Wd*hrD@eJE<2Q`LLt9>w_4^r_YJBe zOi`QTizuIqKiYO|1vgww+u7YeyrLv^QTciQp&);7LDX}HQD+z^b+jIfiXXUT|8Gdb LBE@Gzwx<094HB9E diff --git a/TMessagesProj/src/main/res/drawable-ldpi/addcontact_blue.png b/TMessagesProj/src/main/res/drawable-ldpi/addcontact_blue.png new file mode 100755 index 0000000000000000000000000000000000000000..fd1dd743385bea22d1cbd943090c4adf1556279c GIT binary patch literal 954 zcmaJ=O^ee&7>+EcR2KFm=xNA$P}t_P$!#Iv9W4<3X%={8*tTf>lfXLz3H{hTL_`mOcc)f`1p>*k)` zBztP-E}kd&@(fGUb0kQg!Va6AuWnc)kPEc07H z;CO-M$ddDXL6u}x*anM_Cf*{qr#5wC;ftI!dVq1Lvg~*~X2v3eqCU$jijrywLY^S< z@g%@@k`Lm|OhJdS6L}%_PykXzyNgCxqe-MEDfr=1Hi#ExA_Zd;J7jr=OH;~#mi2$A z?=R6YZo<=e&lHZ^lMu2^7^6|-kjC{kQ&*u{ji8ND)JEtit72n-Fp38#1l5)duJ3z+ zi^lPdIo`5VGl;PrIMCEJnkX=y=c;;j+c0=tlB6Al=WB&>S=4o9M=~U#!f~RJadqU3 zd>G)2>z;DumE3d`{E&FoVdUM1t`Q+0%u`mq)v<^x^%h)rbu5LIT$TjGrj7ll(b*N5 zp4429EjcU)9|mOFBQn;%z7~$jlVD7}+)lo9|IB8kHR14k@zUkr2f>HOTOZ%n|&Z5B~xMK`NL4 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-ldpi/addcontact_green.png b/TMessagesProj/src/main/res/drawable-ldpi/addcontact_green.png new file mode 100755 index 0000000000000000000000000000000000000000..cfa9e2b0344df682c81044a3b37c09f37288c36d GIT binary patch literal 972 zcmaJ=J#W)M7&ZhD3he?ys0`@jb^xjIS7IlzV$u+&G@`E3G@_BZ;Mmv3r1qKfg*cf= znGmY@0StU>NC*Z-gxDfb2WHs#1(uI`Zmg;n zayc`?aG~o{HpArdp>J9(NI(PbIG)D-`uLdzj;*nqvLP6L5jLHb9)=sewVKsySy`LS z-vqf(r2;M_CJ5bKFHl2`9qOvoj;?tY3?ZbYvByExjS46t41vrg6P6%~Kv6g`B`b=! z2qZz2c!4e@A*NJWQKd8(eJu5c?QONHFOPiDlg2g)@l~GhbUIuo$sxSMi`i^8(vYMC zMI?f*N6awc1@mJC9R?P5eBvMvM2cnuwTZ^kNRLx+{fVp>jLJj{#)qcQi<}UpGzJ>R z|DmosK?kG?PvZTja8T>|kgvi3wXsDTw>=-Z^3@`SCPBD{(C)a3l_nx6Xd)jJHxzJv z)A4N732qGWhM|_dfS8^I%eux=1;%bBbwmQooZEoaiDv{KMB8L^lh zb9H33UFeZ9*FNFOQ@PP7xIXo)L+m_+_A*8;7^bW`(_@jQ>W#Se^jMNpxjYSqj~e?| zqsLctdLnZ&w)8L=eCW|>$8@Y;ym@tzK8dBWUZ{mX8h;KC^RbzQx6jV33#SHW`v*Vq z>WqH+^<`=B{^`<{$6Nc0U-lOIcVf=n4==a+2log43)dboG3I;z5_vwi{yTbK<p1AdLO-OdndImJ!-2fkgf?xO!V&hmY&eN^X^y+ znyt)4yKI`xO_R+f!$cEwMp^t!Bs!%g;73xE?GG1Y*wnbFaW4KdlL@{BivB_NhnL*F z@AJOT?|FXD*B$EbeW0Pfr5-_$hG;~H!?n5mZmNOb#jNiJT<)}b2CcnX%F2ocK!Qn4 z0%$ZN4ud!lljBb;fGz~7HkHJnH5l8&%UZ@MmUW!Dj1JKV(&f+TqC5gDR06|_>cg&m z^a+M4Ngp=A#>ki+0%;{OVSv38y$N|@MCOv1|9-S9$3p`dV2NlhGpd?=&WEko<>9`3 zOkn7WiZ$ZHR!I%U`q7YP0F-sIxJ*(E>fxLeOEF$*H%gO~iy&PD<-#eNCpn&C(X|JI z-i&05j|<^7Ur_R4Y0J`ig2-mG&aBI+8N&p{aU4O?1Wn^m12@N2OU&V_*;=t608=&; z-BL6aEn5^NZOrmvkm+g&89f$TH>{d#iGnF3a-vR9PLjxE%5kk|n^qkBOJhTAGcm3M zA`VP#%#dL{Qmqv*%-yXWl@%cyzRyr#QN&R}lgBbZwW5L#gE!8klH`HQ%gHh$;VzM* zaYk}6I7hlYxL0;d62&nTLq-{cXH6jAP! z|8!2}2)1K+yFLd{Sf3=I!tpWSoE(S~*AT>JMulJ^cS*XryzH;WZ9n9P&JXG@G(|Y% z+z!WK+x2_VkCEbiOMT?BaLgWiqUAO@Z0^^o>Uilb(M~ zEeSK#r{cm?Pw_6)ZI@W|dtrLdXER9p!@H+X+oXr59rO9arNYlP>FDfjiQiitA0YU* zeJ5bpu~#~tJ~4}Q9)EoDrQeD#Z^=LNXVvR&nr@jt(lWKbZkij`!Mg%h?|lSGEPgJ% zXtQr+snF6P*Zfm&Bu-xaw0mGXNtK#Q-&N(2YNTy<-CuL>gKx_JxM)wW@K*O@2mb+; C_Q;C> diff --git a/TMessagesProj/src/main/res/drawable-mdpi/addcontact_blue.png b/TMessagesProj/src/main/res/drawable-mdpi/addcontact_blue.png new file mode 100755 index 0000000000000000000000000000000000000000..ec9b9c0280780542ae770a1016c109ab97a01bbb GIT binary patch literal 956 zcmaJ=J!{)Q7#0LV2&81_k}N$G2q~>TPL>o|ST&Ai*M`a%+YoP!ES+uPNT*8YO7>DH zT{?B^&&VGrv~(!6OGwvD9owOF>QV~n$+4Xdb%mt+;CY_+z4v|YWwY^cYjby#VVJFY z&1})}R`zYI)Bl|s_n8hmq|zmA+$V`0A*STw9s+gW9-tPo-N}z1uJuTF zu+Q5WhEM&FvKgjOOhellAp&}6-~|Tz4+kJqw0n3=43=hkeFQ&T$_DYgOtfG^YKH>k#q3B6pk@6Z z>ibJ{Oj_tB-+v0nok@s<7K-sWa%kiFds(PZFGt8GIO<@0x~O7vhzX8|I0WUk3J#9F zz{N>?cZRnty&lBG4jfcB4VEhKp6BYN!+iBf(IiFD@(@k7_@IxBeM3MItxzz~!V0L8PTb+xzQg6<6SLXs(as`@48s^#2$@4$wAt>$u literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/addcontact_green.png b/TMessagesProj/src/main/res/drawable-mdpi/addcontact_green.png new file mode 100755 index 0000000000000000000000000000000000000000..45d6ac2b49e68d78bfd1662fb24aacaa753e02c2 GIT binary patch literal 956 zcmaJ=O^ee|6b+0F!@!8R(n0W%f+$S$)h3;UW=bbX+kh#hEld|KOq16(bdnd7SCbap zxDZ_U@grP|u3Ze`MmM5cm;M3&fH1yvnvM%=Nb){7=iK}5J@0v^-Q3&V-=!#O&ur;k zGG5KToo({J-70=3!%b`qa1V`eVn>jwyJ!f3>Dy!2g|<6?^aWNaYK!*z13a+qD-QA* zJHs%k9}+f2RcmQzJ5z|k5RSb-rGI@mqk-qD^oeM3R;a;=*IGodw`ljB#nh2qx^@Jr zsX_#Nh;5Mir$MZwD!tTI$UNI-X|ROgsY+iYHLyBBLlFcbQz|+f&jU$f__8QT`~eU+ zUSK)$N=3e`h>{{y!0Mq%w8$MPUA?i2MOG?3!8lY{Hc1jDDKRJ-v%D-y-hG zrfb`h#oG8VAa0L{t=}{sJR?_vGxd5u{W1J~eqP&>UcWoKe()ZIazUEk*%m&wzJ0!N k#{8^3@o&9o?oY1laMa7fwRH69>#OWOnMPZGd;IX}9|LM7=>Px# literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/ic_ab_add_member.png b/TMessagesProj/src/main/res/drawable-mdpi/ic_ab_add_member.png deleted file mode 100644 index b36768f14e97ed65818246b017ace43a9307ec46..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1457 zcmbVMZBP_t9N)u{P!B6j87!S`kpf|FU+#_F;SlbHxW>ctypq%g_jVtS9k|_Vcj1n! zvB?>j7)KB=wUHuUOD#vR%uo|`8pnx%7$?HXP(ElWYAQCPV@=N?XMJ$|(9Y~W&;NOT zzyJGx8@;8kq)wkV9YK&(cZt&nS2X^nB*U*7i;cr2U2~Ob%jF6!!YKeL6663t-61Xr ze1H?`-Z~5N5oC%g`pdL3&k~lGLk2F6F+@XQ$VQO-#nCXwR{;$TfS@SZu$xCuV5lhA zuoY$x=?ObPrC1VE!17qBpO01XjDRgJK=Y$4R1g9hhekuylFCMH*o0md?&HS_newPylqM-7K^h6lh*LC6GAw0ACm#%2Q-liE z=PaJI1tl9+scB)BAR>{7A!0PhN|2x!h9O9rplKW;aJ5d-xF{~E83_$epz?|s)_+ zqX}n7ixtn~Er9^Vm?)E#O6YkU-%61##z{MhX)=$ZTyzm#WU)Jo?G_73L7_OobxW$o zNjyl{7NPA)uKkHz)}a7SlNG-#S0}o_TPbU@S}BK7hXc*>aJ(qR*p$2dSzuoD>$;G{*c;wFp0;dufu;ygoH0yIOKtrilS+PqqhJSAPs;hILchF8P`CGU7vk!Nf=ISrs`-NS;^w#C$ z-^hcTR(14ktCMfs`}occ+m)svQr}-b^Je*stS@&fnZD-q`hv>MBi~(|UV4#zIlZSd z&6ujoI=uCY-g0T!tQ%eJx%xFTWb5r|o2@HY|Mu*e?fZXBS@r7C+T{1You%q`zj5rR z)Rb!#JsrE%=G@n>uNc_dd5Ha_WJTeI2E-iv=m2uz>iFIqbkC&+Qx??ZY~L52GVAPu zg`wWpkVC#XZQV)sg9z|SW8>AU{NIm*!nq?Ye;RtYq_$eNvF(=rj{f8e?Wgx{JHEy< zZDaGk-^Vb6)Lo9ZG@txp^@$_rn=Tu$Y)$@q6^1Etpy$HgMFE28|E$ReDefA zf9q1so7J_s)(=LPWbnzi?=&~Ml6Q1}I(n?XaP8;sy{juv(j!AJww)U72<(jiMBT1Z K=K=egb^idANepoS diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/addcontact_blue.png b/TMessagesProj/src/main/res/drawable-xhdpi/addcontact_blue.png new file mode 100755 index 0000000000000000000000000000000000000000..3ba0c9c352faf958ed7aa95c9d9041271147d84f GIT binary patch literal 982 zcmaJ=J#5oJ7_|f{s8ERk5LA^oxeJKKj-AAfPc>CyCvBjvN*bvV5)zJmZA@#Qd%j|~ z0}@CKFd!jyK|&04frX_oF@Tt0U_fH(0&H|DBa{KoX_7J!EZg^^_ulv2_r1G2Gd(fT zKiJQ4+(2d0sIqY=`40E7KN zrfc@vqOCgo_ysT)Lnh!MYJu2W@OOD%H|YB8Ub=zlEpN8m6Vi)IR(n2p#AVH8gb@f)hM@Pv6aR*DGi_~Mo}b083B_8 zQBqYk(U9d7L!`o0pIULs4~IJn1`2KB2GqqqNEEFGUZEP#GTl3Z7j$L)uw5orFfq0Q zQ4-S0kvc%r{6Ez5y6BKr(SE-F6b@^v0TQby#4E&Rjhi1%LIqGK$fB6kFkb3Zai)nW z4x2at`m6%Z&bhvWqwrh{Zb?RLZKOda)p9 ziiVuYsko@Cm!En9Srk9_8K!fbtW@ccHr5*I5*p%!m7=%d~BTgLY@4>!e2 z_Z}SoFm;snZJfM+C4c?v(>pH?jeJAH&)&FOo4+>-@XPYM$tRCL?gpRUUOqCB8hUx` b1b6ThcQxwI|M<1@Gr4J%(zNlscyf1Vy}h5y68uJqjN5rE5D6){vL?k>Bt4|9rQqD`(TGqbZK# z(v>B%#^z(mI5@$+B>nk5n~uJ8ek zmNf_ayq#e9*bf<-<4SXJXggg*K@+vTK!@L7zJkDWb-1Qjq7@pb<1K9yw7R`gcecAu z(S>uTK`GXlfRCsRVt*ruv{;9IU5%}iV*!Fbgm!hf>r}(40s|8S6h4=AL`edw%1e1g zRizmqi;^se>{YW;UQ<*}o&|#kGHb+bX*F|kV2kZ^*r7Dk1fkdK@x2_6Nn4PL#bTl% z%UOoVMq2^3<7^ORh6*N%9O8x4!vRPX?Izx&I%J;ihTw-I*&rIEi6u;k?NE?-F$rl1 zw5k~%FpJd=ra0>05E!c} zIJxEpF78FA`gqIIDnUf;z(EyLhfIO@JXb3ivkS^%Ij<;%q9m2`1=(OjmSja#MA0Y@ zxh8fteH73k*WKePW4TEy_#v}wBH~>|?jpfH=!dL%<9(6G>J7N=cwcg3xdL-WNDBK` zp@&DTdy?g-ZP{kj_$XlAPFP#NdEowHSK?g7oUg~9nzt`azdi$h-hFpr>czu*hu$ww z(uqfh?_4abe|dc4`GJ{lDDwo^J70f)1jm0A+!NQw{MbrHkB$&uRGV1 On^q~Wm`@ijU;6|1z%qFN literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/ic_ab_add_member.png b/TMessagesProj/src/main/res/drawable-xhdpi/ic_ab_add_member.png deleted file mode 100644 index 36803948a35f758444c283c1dfece2ab7175908d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1958 zcmbVNeOME99KQ_)$XuwEl8K&2DkitP+Z)^Qx)-K1Cpbs$u@r9GF$QcmZ#UV%m!*c8 zNoi=7kcGVn79xh&1Io}WO%t<1K}?f;)HKkvAd2j!VEy6KAKmlZeShEI@B8_FKfmwG zbL%qa&J;wBj|2cfpqr&Jure+9Muf578vBy(S@8suZer$Bxl9p3lYr7nnMqLRAZ(<8 zB&@zA$H*iA2yxquCdQU*`g4I8p`5vkWNOYNru=Hq1A51NwHjE zu}I9Ym{5pdiCHXx6{su$mRn?IGp3MWk_2qn&%^L4ts2FY5~)^%CSX{)NGVdvR2r>H zCPOh+(GFvEPB%k1E#z=)I~#ilEBQ|>uBJ(Xp=cvT6%KbnW*)^*?mWr`s?}hep0L=R zL4A6#M)$9*A!++k(yFB?2Y4^ZxcwmnP>k(F1wq27%$fj8WL5%}TS+l&QD8E&NP$Wd zWGFO*xBlPcAuK5**eU<&oZ&6D9fQjUbHFMOCW&;i<3k7M)rPY;>>E7|A4@|#}&X(Mc%YO0Fi(^hZ zL`X{M2*f-2_lhL+(Zgup0AkZuep*>@@>ARPy?sCTWVM_;QTe90WU#HXWOu`F>)ta= z-`F-5<3@8{0kr;Q`&1Vq+f$C-*}=^WGw0yZQL|gYQ=EhTgm)hA3h8x=xD!I7N4CF^ zj~=@0$QzZ>>N|Df!WC`kdmVIL_{iHev0INMalTOC+(xdhZ#s8o>z??EjK+?O6Si)j z!7cZP)fq1B&l_I}Y-?B?g5Le3n~p3Gmw%4Cvd%>86rAmYk{dUF$xG{xYMoLO=gF>8 zho0EDHOgXttmCZ4lngyZVMn0-t!b>zX08?J(#bv>1jb_fK8eV^`$^XcA+~%zK zKq4!QSC=LBzq1hd=?BmBF&FpTkb=ANM|FVG8BZ5Z8vOCjetrGnBVGKf*WiiVM$b-O zt^BFDTfp1>k8HdBlvB0d9On`JmTCIxnI`zLXQ!FAWVv`}Ew)x_QH`>`cx^?_BojzH z&y=MJ+9OupjeP!_>Pczy(pKlY_GeeN)okd@{?NB@qvw~d-uBtRKK{krPFs3B_g8+n zcmIM^!n1t5K*1qfNd9v#F713QI z=ui@Gzu3>vi-aNv{vsCt^0$2?c-Y6ieElfP8(a_7H0E@6aKxOLy+{7qyZF>e<=VQ0H9x*F zEr}0YS-`(;`si%;-GRe160^#tGz*Fwa!(36)#Ln+zFi5e5todMsa{l%t7}7Zu3T%_ z{Jtt`hsNGCa&%Wacgco|am@$X`6J+glvp66CG3s!s*Go>d7pi9_F!3V49B%%d|Sz) z4KMHfGVKGP;=|>GIi;7h)6QMrb7N@?=Xk*QZp%Dw!_){)zNW{tS$MflIMp`#MELO% zPNbXZg6mhDVL9{YZ>lC9`u+x23&i?I2O@GpQLg-4HYW^_b@aZQTG|s8{B!Ek=W1$I HIjjB#GY#ga diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/addcontact_blue.png b/TMessagesProj/src/main/res/drawable-xxhdpi/addcontact_blue.png new file mode 100755 index 0000000000000000000000000000000000000000..a592549b22b6d4a821cb8690beef3a70e531e621 GIT binary patch literal 1014 zcmaJ=O=#3W6pl)Z7JK#wDMNax;wG8wZq`kAUACK~T`;9=w|1!@rpdG$+hk%g?WPs+ z@8rR=7f}Q+f>gW-9tw(w9)!}1P^k!dDGC)l6nb*9-E2L$K9c$4`@Z+)y*CfWMu&TQ zPWLbj(_0=EkW>Ezh*3ykNlw+79 ztX-{DwN$u?r$aV;V1zJWC_pzk=hnW!<2aCYmrl zG&~-1LUg4VsO$fSI!+rMkP148_n*Q+b;(0~1qFD)H)-K!`Xg7KT=J1YuwTV^KF;D; z9TObXu?I@y5*V1YT?;pYvrW9N%VjqphHIj-l4q#`XWN#XQ3VyIL?NBNkcCi94QUx| zs3as+2qjI`k}+4o=7NJ<5_7EsF6_vSTEX$CX9fB8BC<3eJD_=G+3pw%R6FXmxK_tl zpw^Mg(_r|huzwXgKBCt&@_4L5&&`grV)aJ+k6 zd;HEJXLetId-HJR+1IU&`-Op>!S1QP=XXl6=S=7c&qCqbG5Ihy76-JbMz9+>Zr0ZbnV_B9RWg^ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/addcontact_green.png b/TMessagesProj/src/main/res/drawable-xxhdpi/addcontact_green.png new file mode 100755 index 0000000000000000000000000000000000000000..fd4bada3d43829d58fc503fd56b63d988dd501f6 GIT binary patch literal 1012 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 - @@ -35,4 +35,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/layout/settings_change_name_layout.xml b/TMessagesProj/src/main/res/layout/settings_change_name_layout.xml index f8558878..6bdd8e59 100644 --- a/TMessagesProj/src/main/res/layout/settings_change_name_layout.xml +++ b/TMessagesProj/src/main/res/layout/settings_change_name_layout.xml @@ -1,6 +1,6 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-ar/strings.xml b/TMessagesProj/src/main/res/values-ar/strings.xml index f0367e4e..b6bdf565 100644 --- a/TMessagesProj/src/main/res/values-ar/strings.xml +++ b/TMessagesProj/src/main/res/values-ar/strings.xml @@ -160,6 +160,7 @@ آخر ظهور آخر ظهور قم بدعوة صديق + GLOBAL SEARCH إرسال الرسالة إلى... أدخل اسم للمجموعة @@ -198,6 +199,11 @@ إيقاف هذه الصورة هي تصور لمفتاح التشفير لهذه المحادثة السرية مع ]]>%1$s]]>.
    ]]>إذا كانت مطابقة للصورة التي في جهاز ]]>%2$s]]>, فمحادثتكم آمنة ٢٠٠٪.
    ]]>للمزيد نرجو الذهاب إلى telegram.org
    Unknown + INFO + الهاتف + Username + Username already in use + Username invalid تم تعيين كافة الإشعارات افتراضيا حجم نص الرسائل @@ -206,7 +212,6 @@ إلغاء الحظر إضغط بإستمرار على المستخدم لإلغاء الحظر لا توجد جهات اتصال محظورة - رقم هاتفك إشعارات الرسائل التنبيه معاينة الرسالة diff --git a/TMessagesProj/src/main/res/values-de/strings.xml b/TMessagesProj/src/main/res/values-de/strings.xml index 478d7458..8db89f19 100644 --- a/TMessagesProj/src/main/res/values-de/strings.xml +++ b/TMessagesProj/src/main/res/values-de/strings.xml @@ -160,6 +160,7 @@ zul. online zul. online Freunde einladen + GLOBAL SEARCH Sende Nachricht an… Gruppenname @@ -198,6 +199,11 @@ Aus Das ist eine Darstellung des Schlüssels für den Geheimen Chat mit ]]>%1$s]]>.
    ]]>Wenn dieses Bild auf ]]>%2$s\s]]>s Telefon genau so aussieht, ist euer Chat zu 200%% sicher.
    ]]>Erfahre mehr auf telegram.org
    Unknown + INFO + Telefon + Username + Username already in use + Username invalid Alle Einstellungen für Mitteilungen zurücksetzen Textgröße für Nachrichten @@ -206,7 +212,6 @@ Freigeben Gedrückt halten um freizugeben. Keine blockierten Benutzer - DEINE TELEFONNUMMER NACHRICHTEN Benachrichtigung Vorschau diff --git a/TMessagesProj/src/main/res/values-es/strings.xml b/TMessagesProj/src/main/res/values-es/strings.xml index 920f5533..98c9d5fd 100644 --- a/TMessagesProj/src/main/res/values-es/strings.xml +++ b/TMessagesProj/src/main/res/values-es/strings.xml @@ -160,6 +160,7 @@ últ. vez últ. vez el Invitar a amigos + GLOBAL SEARCH Enviar mensaje a... Nombre del grupo @@ -198,6 +199,11 @@ Apagada Esta imagen es una visualización de la clave de cifrado para el chat secreto con ]]>%1$s]]>.
    ]]>Si esta imagen se ve igual en el teléfono de ]]>%2$s]]>, tu chat es seguro en un 200%%.
    ]]>Aprende más en telegram.org
    Unknown + INFO + Teléfono + Username + Username already in use + Username invalid Restablecer las notificaciones Tamaño del texto @@ -206,7 +212,6 @@ Desbloquear Para desbloquear, mantén pulsado sobre un usuario. Sin usuarios bloqueados - TU NÚMERO DE TELÉFONO NOTIFICACIONES DE MENSAJES Alerta Vista previa del mensaje diff --git a/TMessagesProj/src/main/res/values-it/strings.xml b/TMessagesProj/src/main/res/values-it/strings.xml index 581b0807..cdab3e61 100644 --- a/TMessagesProj/src/main/res/values-it/strings.xml +++ b/TMessagesProj/src/main/res/values-it/strings.xml @@ -160,6 +160,7 @@ ultimo accesso ultimo accesso Invita amici + GLOBAL SEARCH Invia messaggio a... Immetti il nome del gruppo @@ -198,6 +199,11 @@ Spento Questa immagine è una visualizzazione della chiave di cifratura per questa chat segreta con ]]>%1$s]]>.
    ]]>Se questa immagine è uguale sul telefono di ]]>%2$s]]>, la chat è sicura al 200%%.
    ]]>Per saperne di più, visita Telegram.org
    Unknown + INFO + Telefono + Username + Username already in use + Username invalid Ripristina tutte le impostazioni di notifica predefinite Dimensione testo messaggi @@ -206,7 +212,6 @@ Sblocca Tieni premuto sull’utente per sbloccarlo. Ancora nessun utente bloccato - IL TUO NUMERO DI TELEFONO NOTIFICHE MESSAGGI Avviso Anteprima messaggio diff --git a/TMessagesProj/src/main/res/values-ko/strings.xml b/TMessagesProj/src/main/res/values-ko/strings.xml index e44c83b9..a61a43b3 100644 --- a/TMessagesProj/src/main/res/values-ko/strings.xml +++ b/TMessagesProj/src/main/res/values-ko/strings.xml @@ -160,6 +160,7 @@ 마지막 접속: 마지막 접속: 친구 초대 + GLOBAL SEARCH 메시지 보내기... 그룹 이름 입력 @@ -198,6 +199,11 @@ 해제 이 이미지는 ]]>%1$s]]>님과의 비밀대화에 사용 중인 암호화 키의 모습입니다.
    ]]>이 이미지가 ]]>%2$s]]>님의 암호화 키와 똑같다면 대화는 200%% 안전합니다.
    ]]>더 자세한 사항은 telegram.org 를 참고해 주세요.
    Unknown + INFO + 전화번호 + Username + Username already in use + Username invalid 모든 알림 설정이 초기화되었습니다 채팅 글자 크기 @@ -206,7 +212,6 @@ 차단 해제 차단을 해제하려면 대화상대를 길게 누르세요. 차단한 친구가 없습니다 - 전화번호 메시지 알림 알림 사용 메시지 미리보기 diff --git a/TMessagesProj/src/main/res/values-nl/strings.xml b/TMessagesProj/src/main/res/values-nl/strings.xml index eb929997..c05fab20 100644 --- a/TMessagesProj/src/main/res/values-nl/strings.xml +++ b/TMessagesProj/src/main/res/values-nl/strings.xml @@ -160,6 +160,7 @@ gezien gezien Vrienden uitnodigen + GLOBAL SEARCH Bericht verzenden naar… Groepsnaam... @@ -198,6 +199,11 @@ Uit Dit is een weergave van de encryptiesleutel voor deze geheime chat met ]]>%1$s]]>.
    ]]>Als deze afbeelding er bij ]]>%2$s]]> hetzelfde uitziet, is jullie gesprek 200%% beveiligd.
    ]]>Lees meer op telegram.org.
    Unknown + INFO + Telefoon + Username + Username already in use + Username invalid Alle meldingsinstellingen herstellen Tekstgrootte berichten @@ -206,7 +212,6 @@ Deblokkeren Houd een gebruiker ingedrukt om hem/haar te deblokkeren. Geen geblokkeerde gebruikers - JE TELEFOONNUMMER BERICHTMELDINGEN Waarschuwing Voorvertoning diff --git a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml index 8a04e1e6..e4a8dadf 100644 --- a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml @@ -160,6 +160,7 @@ visto visto Convidar Amigos + GLOBAL SEARCH Enviar mensagem para... Digite o nome do grupo @@ -198,6 +199,11 @@ Desativado Esta imagem é uma visualização da chave criptográfica para esta conversa secreta com ]]>%1$s]]>.
    ]]>Se esta imagem aparecer da mesma forma no telefone de ]]>%2$s\'s]]>, sua conversa é 200%% segura.
    ]]>Saiba mais em telegram.org
    Unknown + INFO + Telefone + Username + Username already in use + Username invalid Restaurar todas as configurações de notificação Tamanho do texto nas mensagens @@ -206,7 +212,6 @@ Desbloquear Toque e segure no usuário para desbloquear Nenhum usuário bloqueado - SEU NÚMERO DE TELEFONE NOTIFICAÇÕES DE MENSAGENS Alerta Visualização de Mensagem diff --git a/TMessagesProj/src/main/res/values-pt-rPT/strings.xml b/TMessagesProj/src/main/res/values-pt-rPT/strings.xml index 844c5925..89443029 100644 --- a/TMessagesProj/src/main/res/values-pt-rPT/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rPT/strings.xml @@ -160,6 +160,7 @@ visto visto Convidar Amigos + GLOBAL SEARCH Enviar mensagem para... Digite o nome do grupo @@ -198,6 +199,11 @@ Desativado Esta imagem é uma visualização da chave criptográfica para esta conversa secreta com ]]>%1$s]]>.
    ]]>Se esta imagem aparecer da mesma forma no telefone de ]]>%2$s\'s]]>, sua conversa é 200%% segura.
    ]]>Saiba mais em telegram.org
    Unknown + INFO + Telefone + Username + Username already in use + Username invalid Restaurar todas as configurações de notificação Tamanho do texto nas mensagens @@ -206,7 +212,6 @@ Desbloquear Toque e segure no usuário para desbloquear Nenhum usuário bloqueado - SEU NÚMERO DE TELEFONE NOTIFICAÇÕES DE MENSAGENS Alerta Visualização de Mensagem diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index 67d833a2..af943348 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -160,6 +160,7 @@ last seen last seen Invite Friends + GLOBAL SEARCH Send message to... Enter group name @@ -198,6 +199,11 @@ Off This image is a visualization of the encryption key for this secret chat with ]]>%1$s]]>.
    ]]>If this image looks the same on ]]>%2$s\'s]]> phone, your chat is 200%% secure.
    ]]>Learn more at telegram.org
    Unknown + INFO + Phone + Username + Username already in use + Username invalid Reset all notification settings to default Messages Text Size @@ -206,7 +212,6 @@ Unblock Tap and hold on user to unblock. No blocked users yet - YOUR PHONE NUMBER MESSAGE NOTIFICATIONS Alert Message Preview From 87cb843ea0e393961030064a16b4e616b9132e87 Mon Sep 17 00:00:00 2001 From: DrKLO Date: Sat, 18 Oct 2014 03:06:51 +0400 Subject: [PATCH 10/18] Fixed video compression in Android L, bug fixes --- TMessagesProj/build.gradle | 6 +- .../org/telegram/android/ImageReceiver.java | 3 + .../org/telegram/android/MediaController.java | 29 +++++--- .../telegram/android/video/MP4Builder.java | 18 ++++- .../org/telegram/messenger/TLClassStore.java | 1 + .../org/telegram/ui/Cells/ChatActionCell.java | 10 ++- .../java/org/telegram/ui/ChatActivity.java | 2 +- .../src/main/res/values-v21/styles.xml | 74 +++++++++++++++++++ 8 files changed, 121 insertions(+), 22 deletions(-) create mode 100644 TMessagesProj/src/main/res/values-v21/styles.xml diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index f776b919..322e99a2 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -24,8 +24,8 @@ dependencies { } android { - compileSdkVersion 19 - buildToolsVersion '20.0.0' + compileSdkVersion 21 + buildToolsVersion '21.0.0' signingConfigs { debug { @@ -80,7 +80,7 @@ android { defaultConfig { minSdkVersion 8 targetSdkVersion 19 - versionCode 359 + versionCode 361 versionName "1.9.5" } } diff --git a/TMessagesProj/src/main/java/org/telegram/android/ImageReceiver.java b/TMessagesProj/src/main/java/org/telegram/android/ImageReceiver.java index aaa5d0e7..26b13aa7 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/ImageReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/android/ImageReceiver.java @@ -108,6 +108,9 @@ public class ImageReceiver { if (img == null) { isPlaceholder = true; ImageLoader.getInstance().loadImage(fileLocation, httpUrl, this, size, cacheOnly); + if (parentView != null) { + parentView.invalidate(); + } } else { setImageBitmap(img, currentPath); } diff --git a/TMessagesProj/src/main/java/org/telegram/android/MediaController.java b/TMessagesProj/src/main/java/org/telegram/android/MediaController.java index 48e974fe..e9161291 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MediaController.java @@ -2081,12 +2081,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel if (end < 0 || info.presentationTimeUs < end) { info.offset = 0; info.flags = extractor.getSampleFlags(); - if (!isAudio) { - buffer.limit(info.offset + info.size); - buffer.position(info.offset); - buffer.putInt(info.size - 4); - } - if (mediaMuxer.writeSampleData(muxerTrackIndex, buffer, info)) { + if (mediaMuxer.writeSampleData(muxerTrackIndex, buffer, info, isAudio)) { didWriteData(messageObject, file, false, false); } extractor.advance(); @@ -2168,6 +2163,23 @@ public class MediaController implements NotificationCenter.NotificationCenterDel resultWidth = temp; rotationValue = 90; rotateRender = 270; + } else if (Build.VERSION.SDK_INT > 20) { + if (rotationValue == 90) { + int temp = resultHeight; + resultHeight = resultWidth; + resultWidth = temp; + rotationValue = 0; + rotateRender = 270; + } else if (rotationValue == 180) { + rotateRender = 180; + rotationValue = 0; + } else if (rotationValue == 270) { + int temp = resultHeight; + resultHeight = resultWidth; + resultWidth = temp; + rotationValue = 0; + rotateRender = 90; + } } File inputFile = new File(videoPath); @@ -2374,10 +2386,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } if (info.size > 1) { if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) { - encodedData.limit(info.offset + info.size); - encodedData.position(info.offset); - encodedData.putInt(Integer.reverseBytes(info.size - 4)); - if (mediaMuxer.writeSampleData(videoTrackIndex, encodedData, info)) { + if (mediaMuxer.writeSampleData(videoTrackIndex, encodedData, info, false)) { didWriteData(messageObject, cacheFile, false, false); } } else if (videoTrackIndex == -5) { diff --git a/TMessagesProj/src/main/java/org/telegram/android/video/MP4Builder.java b/TMessagesProj/src/main/java/org/telegram/android/video/MP4Builder.java index a04e8d4c..9d9eca96 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/video/MP4Builder.java +++ b/TMessagesProj/src/main/java/org/telegram/android/video/MP4Builder.java @@ -54,12 +54,13 @@ public class MP4Builder { private InterleaveChunkMdat mdat = null; private Mp4Movie currentMp4Movie = null; - FileOutputStream fos = null; + private FileOutputStream fos = null; private FileChannel fc = null; private long dataOffset = 0; private long writedSinceLastMdat = 0; private boolean writeNewMdat = true; - HashMap track2SampleSizes = new HashMap(); + private HashMap track2SampleSizes = new HashMap(); + private ByteBuffer sizeBuffer = null; public MP4Builder createMovie(Mp4Movie mp4Movie) throws Exception { currentMp4Movie = mp4Movie; @@ -74,6 +75,8 @@ public class MP4Builder { mdat = new InterleaveChunkMdat(); + sizeBuffer = ByteBuffer.allocateDirect(4); + return this; } @@ -87,7 +90,7 @@ public class MP4Builder { fos.flush(); } - public boolean writeSampleData(int trackIndex, ByteBuffer byteBuf, MediaCodec.BufferInfo bufferInfo) throws Exception { + public boolean writeSampleData(int trackIndex, ByteBuffer byteBuf, MediaCodec.BufferInfo bufferInfo, boolean isAudio) throws Exception { if (writeNewMdat) { mdat.setContentSize(0); mdat.getBox(fc); @@ -109,9 +112,16 @@ public class MP4Builder { } currentMp4Movie.addSample(trackIndex, dataOffset, bufferInfo); - byteBuf.position(bufferInfo.offset); + byteBuf.position(bufferInfo.offset + (isAudio ? 0 : 4)); byteBuf.limit(bufferInfo.offset + bufferInfo.size); + if (!isAudio) { + sizeBuffer.position(0); + sizeBuffer.putInt(bufferInfo.size - 4); + sizeBuffer.position(0); + fc.write(sizeBuffer); + } + fc.write(byteBuf); dataOffset += bufferInfo.size; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TLClassStore.java b/TMessagesProj/src/main/java/org/telegram/messenger/TLClassStore.java index 6b030372..67a050c2 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TLClassStore.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TLClassStore.java @@ -370,6 +370,7 @@ public class TLClassStore { classStore.put(TLRPC.TL_userRequest_old.constructor, TLRPC.TL_userRequest_old.class); classStore.put(TLRPC.TL_userForeign_old.constructor, TLRPC.TL_userForeign_old.class); classStore.put(TLRPC.TL_userDeleted_old.constructor, TLRPC.TL_userDeleted_old.class); + classStore.put(TLRPC.TL_messageEcryptedAction.constructor, TLRPC.TL_messageEcryptedAction.class); } static TLClassStore store = null; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java index 7dd0b4c9..7b4cae56 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java @@ -278,9 +278,11 @@ public class ChatActionCell extends BaseCell { imageReceiver.draw(canvas, imageReceiver.getImageX(), imageReceiver.getImageY(), imageReceiver.getImageWidth(), imageReceiver.getImageHeight()); } - canvas.save(); - canvas.translate(textXLeft, textY); - textLayout.draw(canvas); - canvas.restore(); + if (textLayout != null) { + canvas.save(); + canvas.translate(textXLeft, textY); + textLayout.draw(canvas); + canvas.restore(); + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index ac0fd5fc..eff669ec 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -926,7 +926,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (visibleItemCount > 0) { - if (firstVisibleItem <= 4) { + if (firstVisibleItem <= 10) { if (!endReached && !loading) { if (messagesByDays.size() != 0) { MessagesController.getInstance().loadMessages(dialog_id, 20, maxMessageId, !cacheEndReaced, minDate, classGuid, false, false, null); diff --git a/TMessagesProj/src/main/res/values-v21/styles.xml b/TMessagesProj/src/main/res/values-v21/styles.xml new file mode 100644 index 00000000..c27fb073 --- /dev/null +++ b/TMessagesProj/src/main/res/values-v21/styles.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 15ac6cdb386c1e98f520774d153dcd5110c20df2 Mon Sep 17 00:00:00 2001 From: DrKLO Date: Mon, 20 Oct 2014 15:30:05 +0400 Subject: [PATCH 11/18] Crash fixes --- .../telegram/android/SendMessagesHelper.java | 12 +++--- .../messenger/ConnectionsManager.java | 1 + .../java/org/telegram/ui/ChatActivity.java | 40 +++++++++++-------- .../java/org/telegram/ui/LaunchActivity.java | 12 +++--- .../org/telegram/ui/Views/NumberPicker.java | 2 +- 5 files changed, 39 insertions(+), 28 deletions(-) diff --git a/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java index d37614a0..a87c5869 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java @@ -373,7 +373,11 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter sendMessage(null, null, null, null, null, null, null, null, audio, null, peer, false, path); } - private int sendMessage(String message, Double lat, Double lon, TLRPC.TL_photo photo, TLRPC.TL_video video, MessageObject msgObj, TLRPC.User user, TLRPC.TL_document document, TLRPC.TL_audio audio, String originalPath, long peer, boolean retry, String path) { + private void sendMessage(String message, Double lat, Double lon, TLRPC.TL_photo photo, TLRPC.TL_video video, MessageObject msgObj, TLRPC.User user, TLRPC.TL_document document, TLRPC.TL_audio audio, String originalPath, long peer, boolean retry, String path) { + if (peer == 0) { + return; + } + TLRPC.Message newMsg = null; int type = -1; int lower_id = (int) peer; @@ -548,7 +552,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter if (high_id == 1) { if (currentChatInfo == null) { processSentMessage(newMsg.id); - return 0; + return; } sendToPeers = new ArrayList(); for (TLRPC.TL_chatParticipant participant : currentChatInfo.participants) { @@ -573,7 +577,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter TLRPC.User sendToUser = MessagesController.getInstance().getUser(lower_id); if (sendToUser == null) { processSentMessage(newMsg.id); - return 0; + return; } if (sendToUser instanceof TLRPC.TL_userForeign || sendToUser instanceof TLRPC.TL_userRequest) { sendToPeer = new TLRPC.TL_inputPeerForeign(); @@ -929,9 +933,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, newMsgObj.messageOwner.id); processSentMessage(newMsgObj.messageOwner.id); - return 0; } - return newMsg != null ? newMsg.id : 0; } private void performSendDelayedMessage(final DelayedMessage message) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java b/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java index a0946ca6..81ed6d88 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java @@ -2438,6 +2438,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. } }); } else if ((connection.transportRequestClass & RPCRequest.RPCRequestClassPush) != 0) { + FileLog.e("tmessages", "call connection closed"); sendingPushPing = false; lastPushPingTime = System.currentTimeMillis() - 60000 * 3 + 4000; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index eff669ec..68e51bdc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -71,7 +71,6 @@ import org.telegram.ui.Cells.ChatContactCell; import org.telegram.ui.Cells.ChatMediaCell; import org.telegram.ui.Cells.ChatMessageCell; import org.telegram.ui.Views.ActionBar.ActionBarLayer; -import org.telegram.ui.Views.ActionBar.ActionBarLayout; import org.telegram.ui.Views.ActionBar.ActionBarMenu; import org.telegram.ui.Views.ActionBar.ActionBarMenuItem; import org.telegram.ui.Views.BackupImageView; @@ -131,7 +130,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private View pagedownButton; private TextView topPanelText; private long dialog_id; - private boolean isBraodcast = false; + private boolean isBroadcast = false; private HashMap selectedMessagesIds = new HashMap(); private HashMap selectedMessagesCanCopyIds = new HashMap(); @@ -241,15 +240,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chatId > 0) { dialog_id = -chatId; } else { - isBraodcast = true; + isBroadcast = true; dialog_id = AndroidUtilities.makeBroadcastId(chatId); } Semaphore semaphore = null; - if (isBraodcast) { + if (isBroadcast) { semaphore = new Semaphore(0); } MessagesController.getInstance().loadChatInfo(currentChat.id, semaphore); - if (isBraodcast) { + if (isBroadcast) { try { semaphore.acquire(); } catch (Exception e) { @@ -1176,7 +1175,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (currentChat.photo != null) { photo = currentChat.photo.photo_small; } - if (isBraodcast) { + if (isBroadcast) { placeHolderId = AndroidUtilities.getBroadcastAvatarForId(currentChat.id); } else { placeHolderId = AndroidUtilities.getGroupAvatarForId(currentChat.id); @@ -1203,9 +1202,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private int getMessageType(MessageObject messageObject) { + if (messageObject == null) { + return -1; + } if (currentEncryptedChat == null) { - boolean isBroadcastError = isBraodcast && messageObject.messageOwner.id <= 0 && messageObject.isSendError(); - if (!isBraodcast && messageObject.messageOwner.id <= 0 && messageObject.isOut() || isBroadcastError) { + boolean isBroadcastError = isBroadcast && messageObject.messageOwner.id <= 0 && messageObject.isSendError(); + if (!isBroadcast && messageObject.messageOwner.id <= 0 && messageObject.isOut() || isBroadcastError) { if (messageObject.isSendError()) { if (!(messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaEmpty)) { return 0; @@ -1447,7 +1449,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (currentChat.photo != null) { newPhoto = currentChat.photo.photo_small; } - if (isBraodcast) { + if (isBroadcast) { placeHolderId = AndroidUtilities.getBroadcastAvatarForId(currentChat.id); } else { placeHolderId = AndroidUtilities.getGroupAvatarForId(currentChat.id); @@ -1458,7 +1460,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } - public boolean openVideoEditor(String videoPath, boolean removeLast, ActionBarLayout parentLayout) { + public boolean openVideoEditor(String videoPath, boolean removeLast) { Bundle args = new Bundle(); args.putString("videoPath", videoPath); VideoEditorActivity fragment = new VideoEditorActivity(args); @@ -1543,7 +1545,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (paused) { startVideoEdit = videoPath; } else { - openVideoEditor(videoPath, false, parentLayout); + openVideoEditor(videoPath, false); } } else { SendMessagesHelper.prepareSendingVideo(videoPath, 0, 0, 0, 0, null, dialog_id); @@ -1735,7 +1737,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (messArr.size() != count) { if (isCache) { cacheEndReaced = true; - if (currentEncryptedChat != null || isBraodcast) { + if (currentEncryptedChat != null || isBroadcast) { endReached = true; } } else { @@ -2102,7 +2104,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (currentChat != null && chatId == currentChat.id) { info = (TLRPC.ChatParticipants)args[1]; updateOnlineCount(); - if (isBraodcast) { + if (isBroadcast) { SendMessagesHelper.getInstance().setCurrentChatInfo(info); } } @@ -2386,7 +2388,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not AndroidUtilities.RunOnUIThread(new Runnable() { @Override public void run() { - openVideoEditor(startVideoEdit, false, parentLayout); + openVideoEditor(startVideoEdit, false); startVideoEdit = null; } }); @@ -2501,6 +2503,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else if (v instanceof ChatActionCell) { message = ((ChatActionCell)v).getMessageObject(); } + if (message == null) { + return; + } final int type = getMessageType(message); selectedObject = null; @@ -2774,7 +2779,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void didSelectDialog(MessagesActivity activity, long did, boolean param) { if (dialog_id != 0 && (forwaringMessage != null || !selectedMessagesIds.isEmpty())) { - if (isBraodcast) { + if (isBroadcast) { param = true; } if (did != dialog_id) { @@ -3178,9 +3183,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not processRowSelect(cell); return; } + MessageObject messageObject = cell.getMessageObject(); Bundle args = new Bundle(); - args.putInt("user_id", message.messageOwner.media.user_id); - args.putString("phone", message.messageOwner.media.phone_number); + args.putInt("user_id", messageObject.messageOwner.media.user_id); + args.putString("phone", messageObject.messageOwner.media.phone_number); presentFragment(new ContactAddActivity(args)); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index f61b30d5..9cc07547 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -661,13 +661,15 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa actionBarLayout.presentFragment(fragment, false, true, true); } - if (!fragment.openVideoEditor(videoPath, true, actionBarLayout)) { - if (!AndroidUtilities.isTablet()) { - actionBarLayout.presentFragment(fragment, true); - } - } else if (!AndroidUtilities.isTablet()) { + if (!AndroidUtilities.isTablet()) { actionBarLayout.addFragmentToStack(fragment, actionBarLayout.fragmentsStack.size() - 1); } + + if (!fragment.openVideoEditor(videoPath, true)) { + if (!AndroidUtilities.isTablet()) { + messageFragment.finishFragment(true); + } + } } else { actionBarLayout.presentFragment(fragment, true); SendMessagesHelper.prepareSendingVideo(videoPath, 0, 0, 0, 0, null, dialog_id); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/NumberPicker.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/NumberPicker.java index 3c94f8f9..6dbffc09 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/NumberPicker.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/NumberPicker.java @@ -166,7 +166,7 @@ public class NumberPicker extends LinearLayout { mInputText.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); mInputText.setGravity(Gravity.CENTER); mInputText.setSingleLine(true); - mInputText.setBackground(null); + mInputText.setBackgroundResource(0); mInputText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18); ViewConfiguration configuration = ViewConfiguration.get(context); From 08a49ea2eabd8954560b5b68a4a09d4b4f83d5d3 Mon Sep 17 00:00:00 2001 From: DrKLO Date: Mon, 20 Oct 2014 22:11:47 +0400 Subject: [PATCH 12/18] Enable screenshot detection --- TMessagesProj/build.gradle | 2 +- .../org/telegram/android/MediaController.java | 139 +++++++++--------- .../java/org/telegram/ui/ChatActivity.java | 4 +- .../main/res/drawable-v21/bar_selector.xml | 4 + .../res/drawable-v21/bar_selector_mode.xml | 4 + .../res/drawable-v21/bar_selector_picker.xml | 4 + .../res/drawable-v21/bar_selector_style.xml | 4 + .../res/drawable-v21/bar_selector_white.xml | 4 + .../main/res/drawable-v21/list_selector.xml | 5 + .../group_profile_add_member_layout.xml | 1 - .../src/main/res/values-ar/strings.xml | 8 +- .../src/main/res/values-de/strings.xml | 8 +- .../src/main/res/values-es/strings.xml | 8 +- .../src/main/res/values-it/strings.xml | 8 +- .../src/main/res/values-ko/strings.xml | 8 +- .../src/main/res/values-nl/strings.xml | 8 +- .../src/main/res/values-pt-rBR/strings.xml | 8 +- .../src/main/res/values-pt-rPT/strings.xml | 8 +- .../src/main/res/values-v21/styles.xml | 2 +- TMessagesProj/src/main/res/values/strings.xml | 8 +- 20 files changed, 153 insertions(+), 92 deletions(-) create mode 100644 TMessagesProj/src/main/res/drawable-v21/bar_selector.xml create mode 100644 TMessagesProj/src/main/res/drawable-v21/bar_selector_mode.xml create mode 100644 TMessagesProj/src/main/res/drawable-v21/bar_selector_picker.xml create mode 100644 TMessagesProj/src/main/res/drawable-v21/bar_selector_style.xml create mode 100644 TMessagesProj/src/main/res/drawable-v21/bar_selector_white.xml create mode 100644 TMessagesProj/src/main/res/drawable-v21/list_selector.xml diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index 322e99a2..64fb45a6 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -25,7 +25,7 @@ dependencies { android { compileSdkVersion 21 - buildToolsVersion '21.0.0' + buildToolsVersion '21.0.1' signingConfigs { debug { diff --git a/TMessagesProj/src/main/java/org/telegram/android/MediaController.java b/TMessagesProj/src/main/java/org/telegram/android/MediaController.java index e9161291..acebe8a2 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MediaController.java @@ -18,6 +18,8 @@ import android.content.IntentFilter; import android.content.SharedPreferences; import android.database.ContentObserver; import android.database.Cursor; +import android.graphics.BitmapFactory; +import android.graphics.Point; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioRecord; @@ -36,7 +38,10 @@ import android.os.Environment; import android.os.ParcelFileDescriptor; import android.os.Vibrator; import android.provider.MediaStore; +import android.util.DisplayMetrics; +import android.view.Display; import android.view.View; +import android.view.WindowManager; import org.telegram.android.video.InputSurface; import org.telegram.android.video.MP4Builder; @@ -58,6 +63,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.lang.ref.WeakReference; +import java.lang.reflect.Method; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.ArrayList; @@ -340,13 +346,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } } } - private String[] mediaProjections = new String[] { - MediaStore.Images.ImageColumns.DATA, - MediaStore.Images.ImageColumns.DISPLAY_NAME, - MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME, - MediaStore.Images.ImageColumns.DATE_TAKEN, - MediaStore.Images.ImageColumns.TITLE - }; + private String[] mediaProjections = null; private static volatile MediaController Instance = null; public static MediaController getInstance() { @@ -413,6 +413,26 @@ public class MediaController implements NotificationCenter.NotificationCenterDel if (UserConfig.isClientActivated()) { checkAutodownloadSettings(); } + + if (Build.VERSION.SDK_INT >= 16) { + mediaProjections = new String[] { + MediaStore.Images.ImageColumns.DATA, + MediaStore.Images.ImageColumns.DISPLAY_NAME, + MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME, + MediaStore.Images.ImageColumns.DATE_TAKEN, + MediaStore.Images.ImageColumns.TITLE, + MediaStore.Images.ImageColumns.WIDTH, + MediaStore.Images.ImageColumns.HEIGHT + }; + } else { + mediaProjections = new String[] { + MediaStore.Images.ImageColumns.DATA, + MediaStore.Images.ImageColumns.DISPLAY_NAME, + MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME, + MediaStore.Images.ImageColumns.DATE_TAKEN, + MediaStore.Images.ImageColumns.TITLE + }; + } } private void startProgressTimer() { @@ -684,7 +704,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } public void startMediaObserver() { - if (android.os.Build.VERSION.SDK_INT > 0) { //disable while it's not perferct + if (android.os.Build.VERSION.SDK_INT < 14) { return; } ApplicationLoader.applicationHandler.removeCallbacks(stopMediaObserverRunnable); @@ -706,7 +726,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } public void stopMediaObserver() { - if (android.os.Build.VERSION.SDK_INT > 0) { //disable while it's not perferct + if (android.os.Build.VERSION.SDK_INT < 14) { return; } if (stopMediaObserverRunnable == null) { @@ -718,6 +738,30 @@ public class MediaController implements NotificationCenter.NotificationCenterDel public void processMediaObserver(Uri uri) { try { + int width = 0; + int height = 0; + + try { + WindowManager windowManager = (WindowManager) ApplicationLoader.applicationContext.getSystemService(Context.WINDOW_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + Point size = new Point(); + windowManager.getDefaultDisplay().getRealSize(size); + width = size.x; + height = size.y; + } else { + try { + Method mGetRawW = Display.class.getMethod("getRawWidth"); + Method mGetRawH = Display.class.getMethod("getRawHeight"); + width = (Integer) mGetRawW.invoke(windowManager.getDefaultDisplay()); + height = (Integer) mGetRawH.invoke(windowManager.getDefaultDisplay()); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + Cursor cursor = ApplicationLoader.applicationContext.getContentResolver().query(uri, mediaProjections, null, null, "date_added DESC LIMIT 1"); final ArrayList screenshotDates = new ArrayList(); if (cursor != null) { @@ -726,75 +770,33 @@ public class MediaController implements NotificationCenter.NotificationCenterDel String data = cursor.getString(0); String display_name = cursor.getString(1); String album_name = cursor.getString(2); - String title = cursor.getString(4); long date = cursor.getLong(3); + String title = cursor.getString(4); + int photoW = 0; + int photoH = 0; + if (Build.VERSION.SDK_INT >= 16) { + photoW = cursor.getInt(5); + photoH = cursor.getInt(6); + } if (data != null && data.toLowerCase().contains("screenshot") || display_name != null && display_name.toLowerCase().contains("screenshot") || album_name != null && album_name.toLowerCase().contains("screenshot") || title != null && title.toLowerCase().contains("screenshot")) { - /*BitmapRegionDecoder bitmapRegionDecoder = null; - boolean added = false; try { - int waitCount = 0; - while (waitCount < 5 && bitmapRegionDecoder == null) { - try { - bitmapRegionDecoder = BitmapRegionDecoder.newInstance(data, true); - if (bitmapRegionDecoder != null) { - break; - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } - Thread.sleep(1000); + if (photoW == 0 || photoH == 0) { + BitmapFactory.Options bmOptions = new BitmapFactory.Options(); + bmOptions.inJustDecodeBounds = true; + BitmapFactory.decodeFile(data, bmOptions); + photoW = bmOptions.outWidth; + photoH = bmOptions.outHeight; } - if (bitmapRegionDecoder != null) { - Bitmap bitmap = bitmapRegionDecoder.decodeRegion(new Rect(0, 0, AndroidUtilities.dp(44), AndroidUtilities.dp(44)), null); - int w = bitmap.getWidth(); - int h = bitmap.getHeight(); - for (int y = 0; y < h; y++) { - int rowCount = 0; - for (int x = 0; x < w; x++) { - int px = bitmap.getPixel(x, y); - if (px == 0xffffffff) { - rowCount++; - } else { - rowCount = 0; - } - if (rowCount > 8) { - break; - } - } - if (rowCount > 8) { - screenshotDates.add(date); - added = true; - break; - } - } - bitmapRegionDecoder.recycle(); - try { - if (bitmap != null) { - bitmap.recycle(); - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - } catch (Exception e) { - FileLog.e("tmessages", e); - try { - if (bitmapRegionDecoder != null) { - bitmapRegionDecoder.recycle(); - } - } catch (Exception e2) { - FileLog.e("tmessages", e2); - } - if (!added) { + if (photoW == 0 || photoH == 0 || (photoW == width && photoH == height || photoH == width && photoW == height)) { screenshotDates.add(date); } - }*/ - screenshotDates.add(date); + } catch (Exception e) { + screenshotDates.add(date); + } } - FileLog.e("tmessages", "screenshot!"); } cursor.close(); } @@ -1205,7 +1207,6 @@ public class MediaController implements NotificationCenter.NotificationCenterDel audioTrackPlayer = new AudioTrack(AudioManager.STREAM_MUSIC, 48000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, playerBufferSize, AudioTrack.MODE_STREAM); audioTrackPlayer.setStereoVolume(1.0f, 1.0f); - //audioTrackPlayer.setNotificationMarkerPosition((int)currentTotalPcmDuration); audioTrackPlayer.setPlaybackPositionUpdateListener(new AudioTrack.OnPlaybackPositionUpdateListener() { @Override public void onMarkerReached(AudioTrack audioTrack) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 68e51bdc..d7832c45 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -2424,10 +2424,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatActivityEnterView.setFieldFocused(false); MessagesController.getInstance().cancelTyping(dialog_id); - /*if (currentEncryptedChat != null) { disabled + if (currentEncryptedChat != null) { chatLeaveTime = System.currentTimeMillis(); updateInformationForScreenshotDetector(); - }*/ + } } private void updateInformationForScreenshotDetector() { diff --git a/TMessagesProj/src/main/res/drawable-v21/bar_selector.xml b/TMessagesProj/src/main/res/drawable-v21/bar_selector.xml new file mode 100644 index 00000000..7c7941ef --- /dev/null +++ b/TMessagesProj/src/main/res/drawable-v21/bar_selector.xml @@ -0,0 +1,4 @@ + + + diff --git a/TMessagesProj/src/main/res/drawable-v21/bar_selector_mode.xml b/TMessagesProj/src/main/res/drawable-v21/bar_selector_mode.xml new file mode 100644 index 00000000..386d01ce --- /dev/null +++ b/TMessagesProj/src/main/res/drawable-v21/bar_selector_mode.xml @@ -0,0 +1,4 @@ + + + diff --git a/TMessagesProj/src/main/res/drawable-v21/bar_selector_picker.xml b/TMessagesProj/src/main/res/drawable-v21/bar_selector_picker.xml new file mode 100644 index 00000000..8c28f1d3 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable-v21/bar_selector_picker.xml @@ -0,0 +1,4 @@ + + + diff --git a/TMessagesProj/src/main/res/drawable-v21/bar_selector_style.xml b/TMessagesProj/src/main/res/drawable-v21/bar_selector_style.xml new file mode 100644 index 00000000..ed6784f5 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable-v21/bar_selector_style.xml @@ -0,0 +1,4 @@ + + + diff --git a/TMessagesProj/src/main/res/drawable-v21/bar_selector_white.xml b/TMessagesProj/src/main/res/drawable-v21/bar_selector_white.xml new file mode 100644 index 00000000..46b44285 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable-v21/bar_selector_white.xml @@ -0,0 +1,4 @@ + + + diff --git a/TMessagesProj/src/main/res/drawable-v21/list_selector.xml b/TMessagesProj/src/main/res/drawable-v21/list_selector.xml new file mode 100644 index 00000000..0ba2177b --- /dev/null +++ b/TMessagesProj/src/main/res/drawable-v21/list_selector.xml @@ -0,0 +1,5 @@ + + + + diff --git a/TMessagesProj/src/main/res/layout/group_profile_add_member_layout.xml b/TMessagesProj/src/main/res/layout/group_profile_add_member_layout.xml index bb5acfc3..60c5e3e7 100644 --- a/TMessagesProj/src/main/res/layout/group_profile_add_member_layout.xml +++ b/TMessagesProj/src/main/res/layout/group_profile_add_member_layout.xml @@ -15,7 +15,6 @@ android:id="@+id/done_button" android:paddingRight="16dp" android:paddingLeft="16dp" - android:background="@drawable/bar_selector" android:minHeight="60dp"/> \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-ar/strings.xml b/TMessagesProj/src/main/res/values-ar/strings.xml index b6bdf565..846b80dd 100644 --- a/TMessagesProj/src/main/res/values-ar/strings.xml +++ b/TMessagesProj/src/main/res/values-ar/strings.xml @@ -202,8 +202,12 @@ INFO الهاتف Username - Username already in use - Username invalid + Your Username + Sorry, this username is already taken. + Sorry, this username is invalid. + A username must have at least 5 characters. + Sorry, a username can't start with a number. + You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.\n\nYou can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters. تم تعيين كافة الإشعارات افتراضيا حجم نص الرسائل diff --git a/TMessagesProj/src/main/res/values-de/strings.xml b/TMessagesProj/src/main/res/values-de/strings.xml index 8db89f19..2880d6f5 100644 --- a/TMessagesProj/src/main/res/values-de/strings.xml +++ b/TMessagesProj/src/main/res/values-de/strings.xml @@ -202,8 +202,12 @@ INFO Telefon Username - Username already in use - Username invalid + Your Username + Sorry, this username is already taken. + Sorry, this username is invalid. + A username must have at least 5 characters. + Sorry, a username can't start with a number. + You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.\n\nYou can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters. Alle Einstellungen für Mitteilungen zurücksetzen Textgröße für Nachrichten diff --git a/TMessagesProj/src/main/res/values-es/strings.xml b/TMessagesProj/src/main/res/values-es/strings.xml index 98c9d5fd..b1fc0208 100644 --- a/TMessagesProj/src/main/res/values-es/strings.xml +++ b/TMessagesProj/src/main/res/values-es/strings.xml @@ -202,8 +202,12 @@ INFO Teléfono Username - Username already in use - Username invalid + Your Username + Sorry, this username is already taken. + Sorry, this username is invalid. + A username must have at least 5 characters. + Sorry, a username can't start with a number. + You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.\n\nYou can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters. Restablecer las notificaciones Tamaño del texto diff --git a/TMessagesProj/src/main/res/values-it/strings.xml b/TMessagesProj/src/main/res/values-it/strings.xml index cdab3e61..46c1f712 100644 --- a/TMessagesProj/src/main/res/values-it/strings.xml +++ b/TMessagesProj/src/main/res/values-it/strings.xml @@ -202,8 +202,12 @@ INFO Telefono Username - Username already in use - Username invalid + Your Username + Sorry, this username is already taken. + Sorry, this username is invalid. + A username must have at least 5 characters. + Sorry, a username can't start with a number. + You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.\n\nYou can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters. Ripristina tutte le impostazioni di notifica predefinite Dimensione testo messaggi diff --git a/TMessagesProj/src/main/res/values-ko/strings.xml b/TMessagesProj/src/main/res/values-ko/strings.xml index a61a43b3..9b62083e 100644 --- a/TMessagesProj/src/main/res/values-ko/strings.xml +++ b/TMessagesProj/src/main/res/values-ko/strings.xml @@ -202,8 +202,12 @@ INFO 전화번호 Username - Username already in use - Username invalid + Your Username + Sorry, this username is already taken. + Sorry, this username is invalid. + A username must have at least 5 characters. + Sorry, a username can't start with a number. + You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.\n\nYou can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters. 모든 알림 설정이 초기화되었습니다 채팅 글자 크기 diff --git a/TMessagesProj/src/main/res/values-nl/strings.xml b/TMessagesProj/src/main/res/values-nl/strings.xml index c05fab20..dcb5fd21 100644 --- a/TMessagesProj/src/main/res/values-nl/strings.xml +++ b/TMessagesProj/src/main/res/values-nl/strings.xml @@ -202,8 +202,12 @@ INFO Telefoon Username - Username already in use - Username invalid + Your Username + Sorry, this username is already taken. + Sorry, this username is invalid. + A username must have at least 5 characters. + Sorry, a username can't start with a number. + You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.\n\nYou can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters. Alle meldingsinstellingen herstellen Tekstgrootte berichten diff --git a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml index e4a8dadf..37f19d0c 100644 --- a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml @@ -202,8 +202,12 @@ INFO Telefone Username - Username already in use - Username invalid + Your Username + Sorry, this username is already taken. + Sorry, this username is invalid. + A username must have at least 5 characters. + Sorry, a username can't start with a number. + You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.\n\nYou can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters. Restaurar todas as configurações de notificação Tamanho do texto nas mensagens diff --git a/TMessagesProj/src/main/res/values-pt-rPT/strings.xml b/TMessagesProj/src/main/res/values-pt-rPT/strings.xml index 89443029..af0f8721 100644 --- a/TMessagesProj/src/main/res/values-pt-rPT/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rPT/strings.xml @@ -202,8 +202,12 @@ INFO Telefone Username - Username already in use - Username invalid + Your Username + Sorry, this username is already taken. + Sorry, this username is invalid. + A username must have at least 5 characters. + Sorry, a username can't start with a number. + You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.\n\nYou can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters. Restaurar todas as configurações de notificação Tamanho do texto nas mensagens diff --git a/TMessagesProj/src/main/res/values-v21/styles.xml b/TMessagesProj/src/main/res/values-v21/styles.xml index c27fb073..e9ca2a04 100644 --- a/TMessagesProj/src/main/res/values-v21/styles.xml +++ b/TMessagesProj/src/main/res/values-v21/styles.xml @@ -27,7 +27,7 @@ @android:color/white @style/ActionBar.Transparent.TMessages.Item @style/Theme.TMessages.ListView - + @drawable/list_selector @style/Theme.TMessages.EditText @drawable/bar_selector_style diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index af943348..c8188486 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -202,8 +202,12 @@ INFO Phone Username - Username already in use - Username invalid + Your Username + Sorry, this username is already taken. + Sorry, this username is invalid. + A username must have at least 5 characters. + Sorry, a username can't start with a number. + You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.\n\nYou can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters. Reset all notification settings to default Messages Text Size From e8cc3bdd3ccb04d148a4c7c91b9215669a0d020d Mon Sep 17 00:00:00 2001 From: DrKLO Date: Wed, 22 Oct 2014 00:35:16 +0400 Subject: [PATCH 13/18] Different improvements --- TMessagesProj/build.gradle | 2 +- .../telegram/android/AndroidUtilities.java | 18 +- .../org/telegram/android/ImageReceiver.java | 158 +++++---- .../org/telegram/android/MediaController.java | 17 +- .../org/telegram/android/MessageObject.java | 9 +- .../telegram/android/MessagesController.java | 8 +- .../org/telegram/android/MessagesStorage.java | 18 +- .../telegram/android/NotificationCenter.java | 1 + .../telegram/android/SendMessagesHelper.java | 9 +- .../Adapters/BaseContactsSearchAdapter.java | 61 ++++ .../ui/Adapters/BaseFragmentAdapter.java | 1 + .../ui/Adapters/ContactsActivityAdapter.java | 13 +- .../ContactsActivitySearchAdapter.java | 61 +--- .../org/telegram/ui/Cells/ChatActionCell.java | 2 +- .../org/telegram/ui/Cells/ChatAudioCell.java | 2 +- .../org/telegram/ui/Cells/ChatBaseCell.java | 2 +- .../telegram/ui/Cells/ChatContactCell.java | 4 +- .../org/telegram/ui/Cells/ChatMediaCell.java | 12 +- .../org/telegram/ui/Cells/ChatOrUserCell.java | 26 +- .../org/telegram/ui/Cells/DialogCell.java | 21 +- .../java/org/telegram/ui/ChatActivity.java | 79 +++-- .../org/telegram/ui/ChatProfileActivity.java | 11 +- .../ui/ChatProfileChangeNameActivity.java | 58 +++- .../telegram/ui/CountrySelectActivity.java | 7 +- .../org/telegram/ui/GroupCreateActivity.java | 9 +- .../telegram/ui/GroupCreateFinalActivity.java | 7 +- .../org/telegram/ui/MessagesActivity.java | 312 ++++++++++-------- .../java/org/telegram/ui/PhotoViewer.java | 6 +- .../org/telegram/ui/SecretPhotoViewer.java | 2 +- .../org/telegram/ui/SettingsActivity.java | 19 +- .../ui/SettingsBlockedUsersActivity.java | 2 +- .../ui/SettingsChangeNameActivity.java | 67 +++- .../ui/SettingsChangeUsernameActivity.java | 210 +++++++++++- .../ui/SettingsNotificationsActivity.java | 17 +- .../org/telegram/ui/UserProfileActivity.java | 13 +- .../telegram/ui/Views/BackupImageView.java | 2 +- .../ui/Views/SettingsSectionLayout.java | 82 +++++ ..._light.9.png => textfield_activated.9.png} | Bin ...lo_light.9.png => textfield_default.9.png} | Bin ...o_light.9.png => textfield_disabled.9.png} | Bin ..._light.9.png => textfield_disabled2.9.png} | Bin ...lo_light.9.png => textfield_focused.9.png} | Bin ..._light.9.png => textfield_activated.9.png} | Bin ...lo_light.9.png => textfield_default.9.png} | Bin ...o_light.9.png => textfield_disabled.9.png} | Bin ..._light.9.png => textfield_disabled2.9.png} | Bin ...lo_light.9.png => textfield_focused.9.png} | Bin ..._light.9.png => textfield_activated.9.png} | Bin ...lo_light.9.png => textfield_default.9.png} | Bin ...o_light.9.png => textfield_disabled.9.png} | Bin ..._light.9.png => textfield_disabled2.9.png} | Bin ...lo_light.9.png => textfield_focused.9.png} | Bin ...holo_edit_text_light.xml => edit_text.xml} | 14 +- .../chat_profile_change_name_layout.xml | 37 --- .../src/main/res/layout-ar/messages_list.xml | 4 +- .../res/layout-ar/notification_layout.xml | 65 ---- .../layout-ar/settings_change_name_layout.xml | 59 ---- .../res/layout-ar/settings_section_layout.xml | 25 -- .../chat_profile_change_name_layout.xml | 38 --- .../src/main/res/layout/messages_list.xml | 5 +- .../main/res/layout/notification_layout.xml | 62 ---- .../layout/settings_change_name_layout.xml | 57 ---- .../res/layout/settings_section_layout.xml | 27 -- .../src/main/res/values-ar/strings.xml | 102 +++--- .../src/main/res/values-de/strings.xml | 86 ++--- .../src/main/res/values-es/strings.xml | 108 +++--- .../src/main/res/values-it/strings.xml | 86 ++--- .../src/main/res/values-ko/strings.xml | 9 +- .../src/main/res/values-nl/strings.xml | 82 ++--- .../src/main/res/values-pt-rBR/strings.xml | 92 +++--- .../src/main/res/values-pt-rPT/strings.xml | 92 +++--- .../src/main/res/values-v21/styles.xml | 2 +- TMessagesProj/src/main/res/values/strings.xml | 10 +- TMessagesProj/src/main/res/values/styles.xml | 2 +- 74 files changed, 1322 insertions(+), 1090 deletions(-) create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseContactsSearchAdapter.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Views/SettingsSectionLayout.java rename TMessagesProj/src/main/res/drawable-hdpi/{holo_textfield_activated_holo_light.9.png => textfield_activated.9.png} (100%) rename TMessagesProj/src/main/res/drawable-hdpi/{holo_textfield_default_holo_light.9.png => textfield_default.9.png} (100%) rename TMessagesProj/src/main/res/drawable-hdpi/{holo_textfield_disabled_focused_holo_light.9.png => textfield_disabled.9.png} (100%) rename TMessagesProj/src/main/res/drawable-hdpi/{holo_textfield_disabled_holo_light.9.png => textfield_disabled2.9.png} (100%) rename TMessagesProj/src/main/res/drawable-hdpi/{holo_textfield_focused_holo_light.9.png => textfield_focused.9.png} (100%) rename TMessagesProj/src/main/res/drawable-mdpi/{holo_textfield_activated_holo_light.9.png => textfield_activated.9.png} (100%) rename TMessagesProj/src/main/res/drawable-mdpi/{holo_textfield_default_holo_light.9.png => textfield_default.9.png} (100%) rename TMessagesProj/src/main/res/drawable-mdpi/{holo_textfield_disabled_focused_holo_light.9.png => textfield_disabled.9.png} (100%) rename TMessagesProj/src/main/res/drawable-mdpi/{holo_textfield_disabled_holo_light.9.png => textfield_disabled2.9.png} (100%) rename TMessagesProj/src/main/res/drawable-mdpi/{holo_textfield_focused_holo_light.9.png => textfield_focused.9.png} (100%) rename TMessagesProj/src/main/res/drawable-xhdpi/{holo_textfield_activated_holo_light.9.png => textfield_activated.9.png} (100%) rename TMessagesProj/src/main/res/drawable-xhdpi/{holo_textfield_default_holo_light.9.png => textfield_default.9.png} (100%) rename TMessagesProj/src/main/res/drawable-xhdpi/{holo_textfield_disabled_focused_holo_light.9.png => textfield_disabled.9.png} (100%) rename TMessagesProj/src/main/res/drawable-xhdpi/{holo_textfield_disabled_holo_light.9.png => textfield_disabled2.9.png} (100%) rename TMessagesProj/src/main/res/drawable-xhdpi/{holo_textfield_focused_holo_light.9.png => textfield_focused.9.png} (100%) rename TMessagesProj/src/main/res/drawable/{holo_edit_text_light.xml => edit_text.xml} (51%) delete mode 100644 TMessagesProj/src/main/res/layout-ar/chat_profile_change_name_layout.xml delete mode 100644 TMessagesProj/src/main/res/layout-ar/notification_layout.xml delete mode 100644 TMessagesProj/src/main/res/layout-ar/settings_change_name_layout.xml delete mode 100644 TMessagesProj/src/main/res/layout-ar/settings_section_layout.xml delete mode 100644 TMessagesProj/src/main/res/layout/chat_profile_change_name_layout.xml delete mode 100644 TMessagesProj/src/main/res/layout/notification_layout.xml delete mode 100644 TMessagesProj/src/main/res/layout/settings_change_name_layout.xml delete mode 100644 TMessagesProj/src/main/res/layout/settings_section_layout.xml diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index 64fb45a6..eeca3f9b 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -80,7 +80,7 @@ android { defaultConfig { minSdkVersion 8 targetSdkVersion 19 - versionCode 361 + versionCode 362 versionName "1.9.5" } } diff --git a/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java index 21c5bc62..b4f28c26 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java @@ -23,6 +23,8 @@ import android.view.Surface; import android.view.View; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.TextView; import org.telegram.messenger.FileLog; import org.telegram.messenger.R; @@ -32,6 +34,7 @@ import org.telegram.ui.ApplicationLoader; import org.telegram.ui.Views.NumberPicker; import java.io.File; +import java.lang.reflect.Field; import java.util.Hashtable; import java.util.Locale; @@ -416,7 +419,7 @@ public class AndroidUtilities { } } - public static AlertDialog.Builder buildTTLAlert(Context context, final TLRPC.EncryptedChat encryptedChat) { + public static AlertDialog.Builder buildTTLAlert(final Context context, final TLRPC.EncryptedChat encryptedChat) { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(LocaleController.getString("MessageLifetime", R.string.MessageLifetime)); final NumberPicker numberPicker = new NumberPicker(context); @@ -483,4 +486,17 @@ public class AndroidUtilities { }); return builder; } + + public static void clearCursorDrawable(EditText editText) { + if (editText == null || Build.VERSION.SDK_INT < 12) { + return; + } + try { + Field mCursorDrawableRes = TextView.class.getDeclaredField("mCursorDrawableRes"); + mCursorDrawableRes.setAccessible(true); + mCursorDrawableRes.setInt(editText, 0); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/android/ImageReceiver.java b/TMessagesProj/src/main/java/org/telegram/android/ImageReceiver.java index 26b13aa7..415bbc5e 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/ImageReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/android/ImageReceiver.java @@ -9,8 +9,13 @@ package org.telegram.android; import android.graphics.Bitmap; +import android.graphics.BitmapShader; import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Shader; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.view.View; @@ -36,6 +41,12 @@ public class ImageReceiver { private boolean isAspectFit = false; private boolean lastCacheOnly = false; private boolean forcePreview = false; + private int roundRadius = 0; + private BitmapShader bitmapShader = null; + private Paint roundPaint = null; + private RectF roundRect = null; + private RectF bitmapRect = null; + private Matrix shaderMatrix = null; public ImageReceiver() { @@ -66,6 +77,7 @@ public class ImageReceiver { last_httpUrl = null; last_filter = null; lastCacheOnly = false; + bitmapShader = null; last_placeholder = placeholder; last_size = 0; currentImage = null; @@ -105,6 +117,7 @@ public class ImageReceiver { last_placeholder = placeholder; last_size = size; lastCacheOnly = cacheOnly; + bitmapShader = null; if (img == null) { isPlaceholder = true; ImageLoader.getInstance().loadImage(fileLocation, httpUrl, this, size, cacheOnly); @@ -123,6 +136,11 @@ public class ImageReceiver { isPlaceholder = false; ImageLoader.getInstance().incrementUseCount(currentPath); currentImage = bitmap; + if (roundRadius != 0) { + bitmapShader = new BitmapShader(bitmap.getBitmap(), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + roundPaint.setShader(bitmapShader); + bitmapRect.set(0, 0, bitmap.getIntrinsicWidth(), bitmap.getIntrinsicHeight()); + } if (parentView != null) { parentView.invalidate(); } @@ -142,6 +160,7 @@ public class ImageReceiver { last_httpUrl = null; last_filter = null; currentImage = null; + bitmapShader = null; last_size = 0; lastCacheOnly = false; if (parentView != null) { @@ -159,6 +178,7 @@ public class ImageReceiver { last_path = null; last_httpUrl = null; last_filter = null; + bitmapShader = null; last_size = 0; lastCacheOnly = false; if (parentView != null) { @@ -196,83 +216,92 @@ public class ImageReceiver { } } - public boolean draw(Canvas canvas, int x, int y, int w, int h) { + public boolean draw(Canvas canvas) { try { Drawable bitmapDrawable = currentImage; if (forcePreview || bitmapDrawable == null && last_placeholder != null && last_placeholder instanceof BitmapDrawable) { bitmapDrawable = last_placeholder; } if (bitmapDrawable != null) { - int bitmapW = bitmapDrawable.getIntrinsicWidth(); - int bitmapH = bitmapDrawable.getIntrinsicHeight(); - float scaleW = bitmapW / (float)w; - float scaleH = bitmapH / (float)h; - - if (isAspectFit) { - float scale = Math.max(scaleW, scaleH); - canvas.save(); - bitmapW /= scale; - bitmapH /= scale; - drawRegion.set(x + (w - bitmapW) / 2, y + (h - bitmapH) / 2, x + (w + bitmapW) / 2, y + (h + bitmapH) / 2); - bitmapDrawable.setBounds(drawRegion); - try { - bitmapDrawable.draw(canvas); - } catch (Exception e) { - if (currentPath != null) { - ImageLoader.getInstance().removeImage(currentPath); - currentPath = null; - } - setImage(last_path, last_httpUrl, last_filter, last_placeholder, last_size, lastCacheOnly); - FileLog.e("tmessages", e); - } - canvas.restore(); + if (bitmapShader != null) { + drawRegion.set(imageX, imageY, imageX + imageW, imageY + imageH); + roundRect.set(imageX, imageY, imageX + imageW, imageY + imageH); + shaderMatrix.reset(); + shaderMatrix.setScale(1.5f, 1.5f); + bitmapShader.setLocalMatrix(shaderMatrix); + canvas.drawRoundRect(roundRect, roundRadius, roundRadius, roundPaint); } else { - if (Math.abs(scaleW - scaleH) > 0.00001f) { + int bitmapW = bitmapDrawable.getIntrinsicWidth(); + int bitmapH = bitmapDrawable.getIntrinsicHeight(); + float scaleW = bitmapW / (float) imageW; + float scaleH = bitmapH / (float) imageH; + + if (isAspectFit) { + float scale = Math.max(scaleW, scaleH); canvas.save(); - canvas.clipRect(x, y, x + w, y + h); - - if (bitmapW / scaleH > w) { - bitmapW /= scaleH; - drawRegion.set(x - (bitmapW - w) / 2, y, x + (bitmapW + w) / 2, y + h); - } else { - bitmapH /= scaleW; - drawRegion.set(x, y - (bitmapH - h) / 2, x + w, y + (bitmapH + h) / 2); - } + bitmapW /= scale; + bitmapH /= scale; + drawRegion.set(imageX + (imageW - bitmapW) / 2, imageY + (imageH - bitmapH) / 2, imageX + (imageW + bitmapW) / 2, imageY + (imageH + bitmapH) / 2); bitmapDrawable.setBounds(drawRegion); - if (isVisible) { - try { - bitmapDrawable.draw(canvas); - } catch (Exception e) { - if (currentPath != null) { - ImageLoader.getInstance().removeImage(currentPath); - currentPath = null; - } - setImage(last_path, last_httpUrl, last_filter, last_placeholder, last_size, lastCacheOnly); - FileLog.e("tmessages", e); + try { + bitmapDrawable.draw(canvas); + } catch (Exception e) { + if (currentPath != null) { + ImageLoader.getInstance().removeImage(currentPath); + currentPath = null; } + setImage(last_path, last_httpUrl, last_filter, last_placeholder, last_size, lastCacheOnly); + FileLog.e("tmessages", e); } - canvas.restore(); } else { - drawRegion.set(x, y, x + w, y + h); - bitmapDrawable.setBounds(drawRegion); - if (isVisible) { - try { - bitmapDrawable.draw(canvas); - } catch (Exception e) { - if (currentPath != null) { - ImageLoader.getInstance().removeImage(currentPath); - currentPath = null; + if (Math.abs(scaleW - scaleH) > 0.00001f) { + canvas.save(); + canvas.clipRect(imageX, imageY, imageX + imageW, imageY + imageH); + + if (bitmapW / scaleH > imageW) { + bitmapW /= scaleH; + drawRegion.set(imageX - (bitmapW - imageW) / 2, imageY, imageX + (bitmapW + imageW) / 2, imageY + imageH); + } else { + bitmapH /= scaleW; + drawRegion.set(imageX, imageY - (bitmapH - imageH) / 2, imageX + imageW, imageY + (bitmapH + imageH) / 2); + } + bitmapDrawable.setBounds(drawRegion); + if (isVisible) { + try { + bitmapDrawable.draw(canvas); + } catch (Exception e) { + if (currentPath != null) { + ImageLoader.getInstance().removeImage(currentPath); + currentPath = null; + } + setImage(last_path, last_httpUrl, last_filter, last_placeholder, last_size, lastCacheOnly); + FileLog.e("tmessages", e); + } + } + + canvas.restore(); + } else { + drawRegion.set(imageX, imageY, imageX + imageW, imageY + imageH); + bitmapDrawable.setBounds(drawRegion); + if (isVisible) { + try { + bitmapDrawable.draw(canvas); + } catch (Exception e) { + if (currentPath != null) { + ImageLoader.getInstance().removeImage(currentPath); + currentPath = null; + } + setImage(last_path, last_httpUrl, last_filter, last_placeholder, last_size, lastCacheOnly); + FileLog.e("tmessages", e); } - setImage(last_path, last_httpUrl, last_filter, last_placeholder, last_size, lastCacheOnly); - FileLog.e("tmessages", e); } } } } return true; } else if (last_placeholder != null) { - drawRegion.set(x, y, x + w, y + h); + drawRegion.set(imageX, imageY, imageX + imageW, imageY + imageH); last_placeholder.setBounds(drawRegion); if (isVisible) { try { @@ -379,4 +408,19 @@ public class ImageReceiver { public void setForcePreview(boolean value) { forcePreview = value; } + + public void setRoundRadius(int value) { + roundRadius = value; + if (roundRadius != 0) { + roundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + roundRect = new RectF(); + shaderMatrix = new Matrix(); + bitmapRect = new RectF(); + } else { + roundPaint = null; + roundRect = null; + shaderMatrix = null; + bitmapRect = null; + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/android/MediaController.java b/TMessagesProj/src/main/java/org/telegram/android/MediaController.java index acebe8a2..1464050f 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MediaController.java @@ -38,7 +38,6 @@ import android.os.Environment; import android.os.ParcelFileDescriptor; import android.os.Vibrator; import android.provider.MediaStore; -import android.util.DisplayMetrics; import android.view.Display; import android.view.View; import android.view.WindowManager; @@ -400,6 +399,8 @@ public class MediaController implements NotificationCenter.NotificationCenterDel NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileDidLoaded); NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileLoadProgressChanged); NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileUploadProgressChanged); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.messagesDeleted); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.removeAllMessagesFromDialog); BroadcastReceiver networkStateReceiver = new BroadcastReceiver() { @Override @@ -900,6 +901,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel deleteLaterArray.clear(); } + @SuppressWarnings("unchecked") @Override public void didReceivedNotification(int id, Object... args) { if (id == NotificationCenter.FileDidFailedLoad) { @@ -963,6 +965,18 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } listenerInProgress = false; processLaterArrays(); + } else if (id == NotificationCenter.messagesDeleted) { + if (playingMessageObject != null) { + ArrayList markAsDeletedMessages = (ArrayList)args[0]; + if (markAsDeletedMessages.contains(playingMessageObject.messageOwner.id)) { + clenupPlayer(false); + } + } + } else if (id == NotificationCenter.removeAllMessagesFromDialog) { + long did = (Long)args[0]; + if (playingMessageObject != null && playingMessageObject.getDialogId() == did) { + clenupPlayer(false); + } } } @@ -1182,6 +1196,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } return true; } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioDidStarted, messageObject); clenupPlayer(true); final File cacheFile = FileLoader.getPathToMessage(messageObject.messageOwner); diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java index 54fd6579..dea61ff8 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java @@ -607,10 +607,17 @@ public class MessageObject { messageOwner.flags &=~ TLRPC.MESSAGE_FLAG_UNREAD; } - public boolean isSecretMedia() { + public boolean isSecretPhoto() { return messageOwner instanceof TLRPC.TL_message_secret && messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && messageOwner.ttl != 0 && messageOwner.ttl <= 60; } + public boolean isSecretMedia() { + return messageOwner instanceof TLRPC.TL_message_secret && + (messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && messageOwner.ttl != 0 && messageOwner.ttl <= 60 || + messageOwner.media instanceof TLRPC.TL_messageMediaAudio || + messageOwner.media instanceof TLRPC.TL_messageMediaVideo); + } + public static void setIsUnread(TLRPC.Message message, boolean unread) { if (unread) { message.flags |= TLRPC.MESSAGE_FLAG_UNREAD; diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java index 722277b2..ea725695 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java @@ -3687,6 +3687,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter newMessage.media.video.key = decryptedMessage.media.key; newMessage.media.video.iv = decryptedMessage.media.iv; newMessage.media.video.mime_type = decryptedMessage.media.mime_type; + if (newMessage.ttl != 0) { + newMessage.ttl = Math.max(newMessage.media.video.duration + 1, newMessage.ttl); + } if (newMessage.media.video.mime_type == null) { newMessage.media.video.mime_type = "video/mp4"; } @@ -3733,6 +3736,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter newMessage.media.audio.dc_id = message.file.dc_id; newMessage.media.audio.duration = decryptedMessage.media.duration; newMessage.media.audio.mime_type = decryptedMessage.media.mime_type; + if (newMessage.ttl != 0) { + newMessage.ttl = Math.max(newMessage.media.audio.duration + 1, newMessage.ttl); + } if (newMessage.media.audio.mime_type == null) { newMessage.media.audio.mime_type = "audio/ogg"; } @@ -3801,7 +3807,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter return null; } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionReadMessages) { if (!serviceMessage.action.random_ids.isEmpty()) { - MessagesStorage.getInstance().createTaskForSecretChat(chat.id, ConnectionsManager.getInstance().getCurrentTime(), message.date, 1, serviceMessage.action.random_ids); + MessagesStorage.getInstance().createTaskForSecretChat(chat.id, ConnectionsManager.getInstance().getCurrentTime(), ConnectionsManager.getInstance().getCurrentTime(), 1, serviceMessage.action.random_ids); } } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionNotifyLayer) { AndroidUtilities.RunOnUIThread(new Runnable() { diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java index 9260ba4a..31e58ea8 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java @@ -2511,8 +2511,20 @@ public class MessagesStorage { }); } - private int getMessageMediaType(TLRPC.Message message) { + private boolean canAddMessageToMedia(TLRPC.Message message) { if (message instanceof TLRPC.TL_message_secret && message.media instanceof TLRPC.TL_messageMediaPhoto && message.ttl != 0 && message.ttl <= 60) { + return false; + } else if (message.media instanceof TLRPC.TL_messageMediaPhoto || message.media instanceof TLRPC.TL_messageMediaVideo) { + return true; + } + return false; + } + + private int getMessageMediaType(TLRPC.Message message) { + if (message instanceof TLRPC.TL_message_secret && ( + message.media instanceof TLRPC.TL_messageMediaPhoto && message.ttl != 0 && message.ttl <= 60 || + message.media instanceof TLRPC.TL_messageMediaAudio || + message.media instanceof TLRPC.TL_messageMediaVideo)) { return 1; } else if (message.media instanceof TLRPC.TL_messageMediaPhoto || message.media instanceof TLRPC.TL_messageMediaVideo) { return 0; @@ -2555,7 +2567,7 @@ public class MessagesStorage { messagesIdsMap.put(message.id, dialog_id); } - if (getMessageMediaType(message) == 0) { + if (canAddMessageToMedia(message)) { if (messageMediaIds.length() > 0) { messageMediaIds.append(","); } @@ -2639,7 +2651,7 @@ public class MessagesStorage { state3.step(); } - if (getMessageMediaType(message) == 0) { + if (canAddMessageToMedia(message)) { state2.requery(); state2.bindInteger(1, messageId); state2.bindLong(2, dialog_id); diff --git a/TMessagesProj/src/main/java/org/telegram/android/NotificationCenter.java b/TMessagesProj/src/main/java/org/telegram/android/NotificationCenter.java index 2a53670a..1b989616 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/NotificationCenter.java +++ b/TMessagesProj/src/main/java/org/telegram/android/NotificationCenter.java @@ -68,6 +68,7 @@ public class NotificationCenter { public final static int screenshotTook = 50007; public final static int albumsDidLoaded = 50008; public final static int audioDidSent = 50009; + public final static int audioDidStarted = 50010; final private HashMap> observers = new HashMap>(); diff --git a/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java index a87c5869..bf7f6a07 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java @@ -597,6 +597,11 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter newMsg.to_id.user_id = encryptedChat.participant_id; } newMsg.ttl = encryptedChat.ttl; + if (newMsg.media instanceof TLRPC.TL_messageMediaAudio) { + newMsg.ttl = Math.max(encryptedChat.ttl, newMsg.media.audio.duration + 1); + } else if (newMsg.media instanceof TLRPC.TL_messageMediaVideo) { + newMsg.ttl = Math.max(encryptedChat.ttl, newMsg.media.video.duration + 1); + } } MessageObject newMsgObj = new MessageObject(newMsg, null, 2); @@ -630,7 +635,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter TLRPC.TL_decryptedMessage reqSend; if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { reqSend = new TLRPC.TL_decryptedMessage(); - reqSend.ttl = encryptedChat.ttl; + reqSend.ttl = newMsg.ttl; } else { reqSend = new TLRPC.TL_decryptedMessage_old(); reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))]; @@ -788,7 +793,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter TLRPC.TL_decryptedMessage reqSend; if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { reqSend = new TLRPC.TL_decryptedMessage(); - reqSend.ttl = encryptedChat.ttl; + reqSend.ttl = newMsg.ttl; } else { reqSend = new TLRPC.TL_decryptedMessage_old(); reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))]; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseContactsSearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseContactsSearchAdapter.java new file mode 100644 index 00000000..bc0b4f9e --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseContactsSearchAdapter.java @@ -0,0 +1,61 @@ +/* + * This is the source code of Telegram for Android v. 1.7.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2014. + */ + +package org.telegram.ui.Adapters; + +import org.telegram.android.AndroidUtilities; +import org.telegram.messenger.ConnectionsManager; +import org.telegram.messenger.RPCRequest; +import org.telegram.messenger.TLObject; +import org.telegram.messenger.TLRPC; + +import java.util.ArrayList; + +public class BaseContactsSearchAdapter extends BaseFragmentAdapter { + + protected ArrayList globalSearch; + private long reqId = 0; + private int lastReqId; + protected String lastFoundUsername = null; + + public void queryServerSearch(final String query) { + if (query == null || query.length() < 5) { + if (reqId != 0) { + ConnectionsManager.getInstance().cancelRpc(reqId, true); + reqId = 0; + } + globalSearch = null; + lastReqId = 0; + notifyDataSetChanged(); + return; + } + TLRPC.TL_contacts_search req = new TLRPC.TL_contacts_search(); + req.q = query; + req.limit = 50; + final int currentReqId = ++lastReqId; + reqId = ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + if (currentReqId == lastReqId) { + if (error == null) { + TLRPC.TL_contacts_found res = (TLRPC.TL_contacts_found) response; + globalSearch = res.users; + lastFoundUsername = query; + notifyDataSetChanged(); + } + } + reqId = 0; + } + }); + } + }, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseFragmentAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseFragmentAdapter.java index e148cf9c..184e06a1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseFragmentAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseFragmentAdapter.java @@ -14,6 +14,7 @@ import android.view.ViewGroup; import android.widget.BaseAdapter; public class BaseFragmentAdapter extends BaseAdapter { + public void onFragmentCreate() { } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivityAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivityAdapter.java index 78cb606e..1bc0b293 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivityAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivityAdapter.java @@ -21,6 +21,7 @@ import org.telegram.android.MessagesController; import org.telegram.messenger.R; import org.telegram.ui.Cells.ChatOrUserCell; import org.telegram.ui.Views.SectionedBaseAdapter; +import org.telegram.ui.Views.SettingsSectionLayout; import java.util.ArrayList; import java.util.HashMap; @@ -202,12 +203,10 @@ public class ContactsActivityAdapter extends SectionedBaseAdapter { if (usersAsSections) { if (section < ContactsController.getInstance().sortedUsersSectionsArray.size()) { if (convertView == null) { - LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - convertView = li.inflate(R.layout.settings_section_layout, parent, false); + convertView = new SettingsSectionLayout(mContext); convertView.setBackgroundColor(0xffffffff); } - TextView textView = (TextView)convertView.findViewById(R.id.settings_section_text); - textView.setText(ContactsController.getInstance().sortedUsersSectionsArray.get(section)); + ((SettingsSectionLayout) convertView).setText(ContactsController.getInstance().sortedUsersSectionsArray.get(section)); return convertView; } } else { @@ -221,12 +220,10 @@ public class ContactsActivityAdapter extends SectionedBaseAdapter { } if (convertView == null) { - LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - convertView = li.inflate(R.layout.settings_section_layout, parent, false); + convertView = new SettingsSectionLayout(mContext); convertView.setBackgroundColor(0xffffffff); } - TextView textView = (TextView)convertView.findViewById(R.id.settings_section_text); - textView.setText(ContactsController.getInstance().sortedContactsSectionsArray.get(section - 1)); + ((SettingsSectionLayout) convertView).setText(ContactsController.getInstance().sortedContactsSectionsArray.get(section - 1)); return convertView; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivitySearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivitySearchAdapter.java index ec2e602b..b1a1f02a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivitySearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivitySearchAdapter.java @@ -9,17 +9,13 @@ package org.telegram.ui.Adapters; import android.content.Context; -import android.view.LayoutInflater; +import android.text.Html; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; import org.telegram.android.AndroidUtilities; import org.telegram.android.LocaleController; -import org.telegram.messenger.ConnectionsManager; import org.telegram.messenger.R; -import org.telegram.messenger.RPCRequest; -import org.telegram.messenger.TLObject; import org.telegram.messenger.TLRPC; import org.telegram.android.ContactsController; import org.telegram.messenger.FileLog; @@ -27,21 +23,19 @@ import org.telegram.android.MessagesController; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; import org.telegram.ui.Cells.ChatOrUserCell; +import org.telegram.ui.Views.SettingsSectionLayout; import java.util.ArrayList; import java.util.HashMap; import java.util.Timer; import java.util.TimerTask; -public class ContactsActivitySearchAdapter extends BaseFragmentAdapter { +public class ContactsActivitySearchAdapter extends BaseContactsSearchAdapter { private Context mContext; private HashMap ignoreUsers; private ArrayList searchResult; private ArrayList searchResultNames; private Timer searchTimer; - private ArrayList globalSearch; - private long reqId = 0; - private int lastReqId; public ContactsActivitySearchAdapter(Context context, HashMap arg1) { mContext = context; @@ -52,7 +46,6 @@ public class ContactsActivitySearchAdapter extends BaseFragmentAdapter { if (query == null) { searchResult = null; searchResultNames = null; - globalSearch = null; queryServerSearch(null); notifyDataSetChanged(); } else { @@ -79,41 +72,6 @@ public class ContactsActivitySearchAdapter extends BaseFragmentAdapter { } } - private void queryServerSearch(String query) { - if (query == null || query.length() < 5) { - if (reqId != 0) { - ConnectionsManager.getInstance().cancelRpc(reqId, true); - reqId = 0; - } - globalSearch = null; - lastReqId = 0; - notifyDataSetChanged(); - return; - } - TLRPC.TL_contacts_search req = new TLRPC.TL_contacts_search(); - req.q = query; - req.limit = 50; - final int currentReqId = ++lastReqId; - reqId = ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() { - @Override - public void run(final TLObject response, final TLRPC.TL_error error) { - AndroidUtilities.RunOnUIThread(new Runnable() { - @Override - public void run() { - if (currentReqId == lastReqId) { - if (error == null) { - TLRPC.TL_contacts_found res = (TLRPC.TL_contacts_found) response; - globalSearch = res.users; - notifyDataSetChanged(); - } - } - reqId = 0; - } - }); - } - }, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors); - } - private void processSearch(final String query) { AndroidUtilities.RunOnUIThread(new Runnable() { @Override @@ -220,10 +178,8 @@ public class ContactsActivitySearchAdapter extends BaseFragmentAdapter { public View getView(int i, View view, ViewGroup viewGroup) { if (i == (searchResult == null ? 0 : searchResult.size())) { if (view == null) { - LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - view = li.inflate(R.layout.settings_section_layout, viewGroup, false); - TextView textView = (TextView)view.findViewById(R.id.settings_section_text); - textView.setText(LocaleController.getString("GlobalSearch", R.string.GlobalSearch)); + view = new SettingsSectionLayout(mContext); + ((SettingsSectionLayout) view).setText(LocaleController.getString("GlobalSearch", R.string.GlobalSearch)); } } else { if (view == null) { @@ -234,7 +190,12 @@ public class ContactsActivitySearchAdapter extends BaseFragmentAdapter { ((ChatOrUserCell) view).useSeparator = (i != getCount() - 1 && i != searchResult.size() - 1); TLRPC.User user = getItem(i); if (user != null) { - ((ChatOrUserCell) view).setData(user, null, null, i < searchResult.size() ? searchResultNames.get(i) : null, i > searchResult.size() ? "@" + user.username : null); + CharSequence username = null; + if (i > searchResult.size() && user.username != null) { + username = Html.fromHtml(String.format("@%s%s", user.username.substring(0, lastFoundUsername.length()), user.username.substring(lastFoundUsername.length()))); + } + + ((ChatOrUserCell) view).setData(user, null, null, i < searchResult.size() ? searchResultNames.get(i) : null, username); if (ignoreUsers != null) { if (ignoreUsers.containsKey(user.id)) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java index 7b4cae56..02849344 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java @@ -275,7 +275,7 @@ public class ChatActionCell extends BaseCell { backgroundDrawable.draw(canvas); if (currentMessageObject.type == 11) { - imageReceiver.draw(canvas, imageReceiver.getImageX(), imageReceiver.getImageY(), imageReceiver.getImageWidth(), imageReceiver.getImageHeight()); + imageReceiver.draw(canvas); } if (textLayout != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java index 34e8e74a..4569a709 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java @@ -393,7 +393,7 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega } if (needAvatarImage) { - avatarImage.draw(canvas, avatarImage.getImageX(), avatarImage.getImageY(), avatarImage.getImageHeight(), avatarImage.getImageHeight()); + avatarImage.draw(canvas); } canvas.save(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java index ebc90b2c..b3ad22bf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java @@ -430,7 +430,7 @@ public class ChatBaseCell extends BaseCell { } if (isAvatarVisible) { - avatarImage.draw(canvas, AndroidUtilities.dp(6), layoutHeight - AndroidUtilities.dp(45), AndroidUtilities.dp(42), AndroidUtilities.dp(42)); + avatarImage.draw(canvas); } Drawable currentBackgroundDrawable = null; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java index 1621d812..4803d411 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java @@ -207,7 +207,7 @@ public class ChatContactCell extends ChatBaseCell { } phone = PhoneFormat.getInstance().format(phone); } else { - phone = LocaleController.getString("Unknown", R.string.Unknown); + phone = LocaleController.getString("NumberUnknown", R.string.NumberUnknown); } int phoneWidth = Math.min((int) Math.ceil(phonePaint.measureText(phone)), maxWidth); stringFinal = TextUtils.ellipsize(phone.replace("\n", " "), phonePaint, phoneWidth, TextUtils.TruncateAt.END); @@ -260,7 +260,7 @@ public class ChatContactCell extends ChatBaseCell { return; } - avatarImage.draw(canvas, avatarImage.getImageX(), avatarImage.getImageY(), avatarImage.getImageWidth(), avatarImage.getImageWidth()); + avatarImage.draw(canvas); if (nameLayout != null) { canvas.save(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java index 8952b629..bd4bf6e3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java @@ -213,7 +213,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD } } } - if (imagePressed && currentMessageObject.isSecretMedia()) { + if (imagePressed && currentMessageObject.isSecretPhoto()) { imagePressed = false; } else if (result) { startCheckLongPress(); @@ -568,7 +568,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD w = timeWidthTotal; } - if (currentMessageObject.isSecretMedia()) { + if (currentMessageObject.isSecretPhoto()) { if (AndroidUtilities.isTablet()) { w = h = (int) (AndroidUtilities.getMinTabletSide() * 0.5f); } else { @@ -616,7 +616,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD photoImage.setImageBitmap(messageObject.isOut() ? placeholderOutDrawable : placeholderInDrawable); } } - photoImage.setForcePreview(messageObject.isSecretMedia()); + photoImage.setForcePreview(messageObject.isSecretPhoto()); invalidate(); } @@ -813,7 +813,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD canvas.restore(); } else { photoImage.setVisible(!PhotoViewer.getInstance().isShowingImage(currentMessageObject), false); - imageDrawn = photoImage.draw(canvas, photoImage.getImageX(), photoImage.getImageY(), photoWidth, photoHeight); + imageDrawn = photoImage.draw(canvas); drawTime = photoImage.getVisible(); } @@ -873,7 +873,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD currentButtonDrawable.draw(canvas); } - if (buttonState == -1 && currentMessageObject.isSecretMedia()) { + if (buttonState == -1 && currentMessageObject.isSecretPhoto()) { int drawable = 5; if (currentMessageObject.messageOwner.destroyTime != 0) { if (currentMessageObject.isOut()) { @@ -912,7 +912,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD infoLayout.draw(canvas); canvas.restore(); } - } else if (infoLayout != null && (buttonState == 1 || buttonState == 0 || buttonState == 3 || currentMessageObject.isSecretMedia())) { + } else if (infoLayout != null && (buttonState == 1 || buttonState == 0 || buttonState == 3 || currentMessageObject.isSecretPhoto())) { infoPaint.setColor(0xffffffff); setDrawableBounds(mediaBackgroundDrawable, photoImage.getImageX() + AndroidUtilities.dp(4), photoImage.getImageY() + AndroidUtilities.dp(4), infoWidth + AndroidUtilities.dp(8) + infoOffset, AndroidUtilities.dpf(16.5f)); mediaBackgroundDrawable.draw(canvas); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatOrUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatOrUserCell.java index 4b782b91..7008878d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatOrUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatOrUserCell.java @@ -41,7 +41,7 @@ public class ChatOrUserCell extends BaseCell { private CharSequence currentName; private ImageReceiver avatarImage; - private String subLabel; + private CharSequence subLabel; private ChatOrUserCellLayout cellLayout; private TLRPC.User user = null; @@ -112,7 +112,7 @@ public class ChatOrUserCell extends BaseCell { } } - public void setData(TLRPC.User u, TLRPC.Chat c, TLRPC.EncryptedChat ec, CharSequence n, String s) { + public void setData(TLRPC.User u, TLRPC.Chat c, TLRPC.EncryptedChat ec, CharSequence n, CharSequence s) { currentName = n; user = u; chat = c; @@ -236,6 +236,15 @@ public class ChatOrUserCell extends BaseCell { return; } + if (useSeparator) { + int h = getMeasuredHeight(); + if (!usePadding) { + canvas.drawLine(0, h - 1, getMeasuredWidth(), h - 1, linePaint); + } else { + canvas.drawLine(AndroidUtilities.dp(11), h - 1, getMeasuredWidth() - AndroidUtilities.dp(11), h - 1, linePaint); + } + } + if (drawAlpha != 1) { canvas.saveLayerAlpha(0, 0, canvas.getWidth(), canvas.getHeight(), (int)(255 * drawAlpha), Canvas.HAS_ALPHA_LAYER_SAVE_FLAG); } @@ -263,16 +272,7 @@ public class ChatOrUserCell extends BaseCell { canvas.restore(); } - avatarImage.draw(canvas, cellLayout.avatarLeft, cellLayout.avatarTop, AndroidUtilities.dp(50), AndroidUtilities.dp(50)); - - if (useSeparator) { - int h = getMeasuredHeight(); - if (!usePadding) { - canvas.drawLine(0, h - 1, getMeasuredWidth(), h, linePaint); - } else { - canvas.drawLine(AndroidUtilities.dp(11), h - 1, getMeasuredWidth() - AndroidUtilities.dp(11), h, linePaint); - } - } + avatarImage.draw(canvas); } private class ChatOrUserCellLayout { @@ -381,7 +381,7 @@ public class ChatOrUserCell extends BaseCell { onlineLeft = usePadding ? AndroidUtilities.dp(11) : 0; } - String onlineString = ""; + CharSequence onlineString = ""; TextPaint currentOnlinePaint = offlinePaint; if (subLabel != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java index 99970c90..f13332df 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java @@ -10,6 +10,7 @@ package org.telegram.ui.Cells; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.text.Html; import android.text.Layout; @@ -48,6 +49,8 @@ public class DialogCell extends BaseCell { private static Drawable groupDrawable; private static Drawable broadcastDrawable; + private static Paint linePaint; + private TLRPC.TL_dialog currentDialog; private ImageReceiver avatarImage; @@ -57,6 +60,8 @@ public class DialogCell extends BaseCell { private TLRPC.EncryptedChat encryptedChat = null; private CharSequence lastPrintString = null; + public boolean useSeparator = false; + private void init() { if (namePaint == null) { namePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); @@ -85,6 +90,11 @@ public class DialogCell extends BaseCell { messagePaint.setColor(0xff808080); } + if (linePaint == null) { + linePaint = new Paint(); + linePaint.setColor(0xffdcdcdc); + } + if (messagePrintingPaint == null) { messagePrintingPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); messagePrintingPaint.setTextSize(AndroidUtilities.dp(16)); @@ -340,7 +350,16 @@ public class DialogCell extends BaseCell { canvas.restore(); } - avatarImage.draw(canvas, cellLayout.avatarLeft, cellLayout.avatarTop, AndroidUtilities.dp(54), AndroidUtilities.dp(54)); + avatarImage.draw(canvas); + + if (useSeparator) { + int h = getMeasuredHeight(); + if (AndroidUtilities.isTablet()) { + canvas.drawLine(0, h - 1, getMeasuredWidth(), h - 1, linePaint); + } else { + canvas.drawLine(AndroidUtilities.dp(11), h - 1, getMeasuredWidth() - AndroidUtilities.dp(11), h - 1, linePaint); + } + } } private class DialogCellLayout { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index d7832c45..a22bb862 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -367,6 +367,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not NotificationCenter.getInstance().addObserver(this, NotificationCenter.blockedUsersDidLoaded); NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileNewChunkAvailable); NotificationCenter.getInstance().addObserver(this, NotificationCenter.didCreatedNewDeleteTask); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioDidStarted); super.onFragmentCreate(); @@ -419,6 +420,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not NotificationCenter.getInstance().removeObserver(this, NotificationCenter.blockedUsersDidLoaded); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.FileNewChunkAvailable); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didCreatedNewDeleteTask); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioDidStarted); if (AndroidUtilities.isTablet()) { NotificationCenter.getInstance().postNotificationName(NotificationCenter.openedChatChanged, dialog_id, true); } @@ -838,7 +840,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } final ChatMediaCell cell = (ChatMediaCell)view; final MessageObject messageObject = cell.getMessageObject(); - if (messageObject == null || !messageObject.isSecretMedia() || !cell.getPhotoImage().isInsideImage(x, y - top)) { + if (messageObject == null || !messageObject.isSecretPhoto() || !cell.getPhotoImage().isInsideImage(x, y - top)) { break; } File file = FileLoader.getPathToMessage(messageObject.messageOwner); @@ -858,9 +860,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatListView.setOnItemClickListener(null); chatListView.setLongClickable(false); openSecretPhotoRunnable = null; - if (!messageObject.isOut() && messageObject.messageOwner.destroyTime == 0) { - MessagesController.getInstance().markMessageAsRead(dialog_id, messageObject.messageOwner.random_id); - messageObject.messageOwner.destroyTime = messageObject.messageOwner.ttl + ConnectionsManager.getInstance().getCurrentTime(); + if (sendSecretMessageRead(messageObject)) { cell.invalidate(); } SecretPhotoViewer.getInstance().setParentActivity(getParentActivity()); @@ -1026,6 +1026,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return fragmentView; } + private boolean sendSecretMessageRead(MessageObject messageObject) { + if (messageObject == null || messageObject.isOut() || !messageObject.isSecretMedia() || messageObject.messageOwner.destroyTime != 0) { + return false; + } + MessagesController.getInstance().markMessageAsRead(dialog_id, messageObject.messageOwner.random_id); + messageObject.messageOwner.destroyTime = messageObject.messageOwner.ttl + ConnectionsManager.getInstance().getCurrentTime(); + return true; + } + private void scrollToLastMessage() { if (unread_end_reached || first_unread_id == 0) { chatListView.setSelectionFromTop(messages.size() - 1, -100000 - chatListView.getPaddingTop()); @@ -1853,6 +1862,18 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not boolean hasFromMe = false; ArrayList arr = (ArrayList)args[1]; + if (currentEncryptedChat != null && arr.size() == 1) { + MessageObject messageObject = arr.get(0); + + if (messageObject.isOut() && messageObject.messageOwner.action instanceof TLRPC.TL_messageActionTTLChange && getParentActivity() != null && AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) < 17 && currentEncryptedChat.ttl > 0 && currentEncryptedChat.ttl <= 60) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(R.string.OK, null); + builder.setMessage(LocaleController.formatString("CompatibilityChat", R.string.CompatibilityChat, currentUser.first_name, currentUser.first_name)); + showAlertDialog(builder); + } + } + if (!unread_end_reached) { int currentMaxDate = Integer.MIN_VALUE; int currentMinMsgId = Integer.MIN_VALUE; @@ -2166,24 +2187,27 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } else if (id == NotificationCenter.removeAllMessagesFromDialog) { - messages.clear(); - messagesByDays.clear(); - messagesDict.clear(); - progressView.setVisibility(View.GONE); - chatListView.setEmptyView(emptyViewContainer); - if (currentEncryptedChat == null) { - maxMessageId = Integer.MAX_VALUE; - minMessageId = Integer.MIN_VALUE; - } else { - maxMessageId = Integer.MIN_VALUE; - minMessageId = Integer.MAX_VALUE; + long did = (Long)args[0]; + if (dialog_id == did) { + messages.clear(); + messagesByDays.clear(); + messagesDict.clear(); + progressView.setVisibility(View.GONE); + chatListView.setEmptyView(emptyViewContainer); + if (currentEncryptedChat == null) { + maxMessageId = Integer.MAX_VALUE; + minMessageId = Integer.MIN_VALUE; + } else { + maxMessageId = Integer.MIN_VALUE; + minMessageId = Integer.MAX_VALUE; + } + maxDate = Integer.MIN_VALUE; + minDate = 0; + selectedMessagesIds.clear(); + selectedMessagesCanCopyIds.clear(); + actionBarLayer.hideActionMode(); + chatAdapter.notifyDataSetChanged(); } - maxDate = Integer.MIN_VALUE; - minDate = 0; - selectedMessagesIds.clear(); - selectedMessagesCanCopyIds.clear(); - actionBarLayer.hideActionMode(); - chatAdapter.notifyDataSetChanged(); } else if (id == NotificationCenter.screenshotTook) { updateInformationForScreenshotDetector(); } else if (id == NotificationCenter.blockedUsersDidLoaded) { @@ -2221,6 +2245,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (changed) { updateVisibleRows(); } + } else if (id == NotificationCenter.audioDidStarted) { + MessageObject messageObject = (MessageObject)args[0]; + sendSecretMessageRead(messageObject); } } @@ -2431,6 +2458,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void updateInformationForScreenshotDetector() { + if (currentEncryptedChat == null) { + return; + } ArrayList visibleMessages = new ArrayList(); if (chatListView != null) { int count = chatListView.getChildCount(); @@ -2893,9 +2923,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(R.string.OK, null); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); if (message.type == 3) { - builder.setMessage(R.string.NoPlayerInstalled); + builder.setMessage(LocaleController.getString("NoPlayerInstalled", R.string.NoPlayerInstalled)); } else { builder.setMessage(LocaleController.formatString("NoHandleAppInstalled", R.string.NoHandleAppInstalled, message.messageOwner.media.document.mime_type)); } @@ -3104,6 +3134,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not PhotoViewer.getInstance().setParentActivity(getParentActivity()); PhotoViewer.getInstance().openPhoto(message, ChatActivity.this); } else if (message.type == 3) { + sendSecretMessageRead(message); try { File f = null; if (message.messageOwner.attachPath != null && message.messageOwner.attachPath.length() != 0) { @@ -3201,7 +3232,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setItems(new CharSequence[] {LocaleController.getString("Copy", R.string.Copy), LocaleController.getString("Call", R.string.Call)}, new DialogInterface.OnClickListener() { + builder.setItems(new CharSequence[]{LocaleController.getString("Copy", R.string.Copy), LocaleController.getString("Call", R.string.Call)}, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { if (i == 1) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileActivity.java index d3253ada..8c56eca9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileActivity.java @@ -42,6 +42,7 @@ import org.telegram.ui.Views.ActionBar.ActionBarMenu; import org.telegram.ui.Views.AvatarUpdater; import org.telegram.ui.Views.BackupImageView; import org.telegram.ui.Views.ActionBar.BaseFragment; +import org.telegram.ui.Views.SettingsSectionLayout; import java.util.ArrayList; import java.util.Collections; @@ -646,21 +647,19 @@ public class ChatProfileActivity extends BaseFragment implements NotificationCen return view; } else if (type == 1) { if (view == null) { - LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - view = li.inflate(R.layout.settings_section_layout, viewGroup, false); + view = new SettingsSectionLayout(mContext); } - TextView textView = (TextView)view.findViewById(R.id.settings_section_text); if (i == settingsSectionRow) { - textView.setText(LocaleController.getString("SETTINGS", R.string.SETTINGS)); + ((SettingsSectionLayout) view).setText(LocaleController.getString("SETTINGS", R.string.SETTINGS)); } else if (i == sharedMediaSectionRow) { - textView.setText(LocaleController.getString("SHAREDMEDIA", R.string.SHAREDMEDIA)); + ((SettingsSectionLayout) view).setText(LocaleController.getString("SHAREDMEDIA", R.string.SHAREDMEDIA)); } else if (i == membersSectionRow) { TLRPC.Chat chat = MessagesController.getInstance().getChat(chat_id); int count = chat.participants_count; if (info != null) { count = info.participants.size(); } - textView.setText(LocaleController.formatPluralString("Members", count).toUpperCase()); + ((SettingsSectionLayout) view).setText(LocaleController.formatPluralString("Members", count).toUpperCase()); } } else if (type == 2) { if (view == null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileChangeNameActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileChangeNameActivity.java index 6bafe568..a77ea02e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileChangeNameActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileChangeNameActivity.java @@ -11,6 +11,9 @@ package org.telegram.ui; import android.app.Activity; import android.content.SharedPreferences; import android.os.Bundle; +import android.text.InputType; +import android.util.TypedValue; +import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -18,6 +21,7 @@ import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.widget.Button; import android.widget.EditText; +import android.widget.LinearLayout; import android.widget.TextView; import org.telegram.android.AndroidUtilities; @@ -26,6 +30,7 @@ import org.telegram.messenger.TLRPC; import org.telegram.android.MessagesController; import org.telegram.messenger.R; import org.telegram.ui.Views.ActionBar.BaseFragment; +import org.telegram.ui.Views.SettingsSectionLayout; public class ChatProfileChangeNameActivity extends BaseFragment { private EditText firstNameField; @@ -71,16 +76,27 @@ public class ChatProfileChangeNameActivity extends BaseFragment { TextView textView = (TextView)doneButton.findViewById(R.id.done_button_text); textView.setText(LocaleController.getString("Done", R.string.Done).toUpperCase()); - fragmentView = inflater.inflate(R.layout.chat_profile_change_name_layout, container, false); - TLRPC.Chat currentChat = MessagesController.getInstance().getChat(chat_id); - firstNameField = (EditText)fragmentView.findViewById(R.id.first_name_field); - if (chat_id > 0) { - firstNameField.setHint(LocaleController.getString("GroupName", R.string.GroupName)); - } else { - firstNameField.setHint(LocaleController.getString("EnterListName", R.string.EnterListName)); - } + fragmentView = new LinearLayout(inflater.getContext()); + fragmentView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + fragmentView.setPadding(AndroidUtilities.dp(16), AndroidUtilities.dp(8), AndroidUtilities.dp(16), 0); + ((LinearLayout) fragmentView).setOrientation(LinearLayout.VERTICAL); + + SettingsSectionLayout settingsSectionLayout = new SettingsSectionLayout(inflater.getContext()); + ((LinearLayout) fragmentView).addView(settingsSectionLayout); + + firstNameField = new EditText(inflater.getContext()); + firstNameField.setText(currentChat.title); + firstNameField.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 19); + firstNameField.setHintTextColor(0xffa3a3a3); + firstNameField.setTextColor(0xff000000); + firstNameField.setPadding(AndroidUtilities.dp(15), 0, AndroidUtilities.dp(15), AndroidUtilities.dp(15)); + firstNameField.setMaxLines(3); + firstNameField.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + firstNameField.setInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT); + firstNameField.setImeOptions(EditorInfo.IME_ACTION_DONE); + AndroidUtilities.clearCursorDrawable(firstNameField); firstNameField.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { @@ -91,15 +107,25 @@ public class ChatProfileChangeNameActivity extends BaseFragment { return false; } }); - firstNameField.setText(currentChat.title); - firstNameField.setSelection(firstNameField.length()); - - TextView headerLabel = (TextView)fragmentView.findViewById(R.id.settings_section_text); - if (chat_id > 0) { - headerLabel.setText(LocaleController.getString("EnterGroupNameTitle", R.string.EnterGroupNameTitle)); - } else { - headerLabel.setText(LocaleController.getString("EnterListName", R.string.EnterListName).toUpperCase()); + if (LocaleController.isRTL) { + firstNameField.setGravity(Gravity.RIGHT); } + + ((LinearLayout) fragmentView).addView(firstNameField); + LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)firstNameField.getLayoutParams(); + layoutParams.topMargin = AndroidUtilities.dp(15); + layoutParams.width = LinearLayout.LayoutParams.MATCH_PARENT; + layoutParams.height = LinearLayout.LayoutParams.WRAP_CONTENT; + firstNameField.setLayoutParams(layoutParams); + + if (chat_id > 0) { + settingsSectionLayout.setText(LocaleController.getString("EnterGroupNameTitle", R.string.EnterGroupNameTitle)); + firstNameField.setHint(LocaleController.getString("GroupName", R.string.GroupName)); + } else { + settingsSectionLayout.setText(LocaleController.getString("EnterListName", R.string.EnterListName).toUpperCase()); + firstNameField.setHint(LocaleController.getString("EnterListName", R.string.EnterListName)); + } + firstNameField.setSelection(firstNameField.length()); } else { ViewGroup parent = (ViewGroup)fragmentView.getParent(); if (parent != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CountrySelectActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CountrySelectActivity.java index 332381d6..9a733f9f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CountrySelectActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CountrySelectActivity.java @@ -31,6 +31,7 @@ import org.telegram.ui.Views.ActionBar.ActionBarMenuItem; import org.telegram.ui.Views.ActionBar.BaseFragment; import org.telegram.ui.Views.PinnedHeaderListView; import org.telegram.ui.Views.SectionedBaseAdapter; +import org.telegram.ui.Views.SettingsSectionLayout; import java.io.BufferedReader; import java.io.InputStream; @@ -484,12 +485,10 @@ public class CountrySelectActivity extends BaseFragment { @Override public View getSectionHeaderView(int section, View convertView, ViewGroup parent) { if (convertView == null) { - LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - convertView = li.inflate(R.layout.settings_section_layout, parent, false); + convertView = new SettingsSectionLayout(mContext); convertView.setBackgroundColor(0xfffafafa); } - TextView textView = (TextView)convertView.findViewById(R.id.settings_section_text); - textView.setText(sortedCountries.get(section).toUpperCase()); + ((SettingsSectionLayout) convertView).setText(sortedCountries.get(section).toUpperCase()); return convertView; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java index 52395ca1..a8eccbdb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java @@ -51,6 +51,7 @@ import org.telegram.ui.Views.BackupImageView; import org.telegram.ui.Views.ActionBar.BaseFragment; import org.telegram.ui.Views.PinnedHeaderListView; import org.telegram.ui.Views.SectionedBaseAdapter; +import org.telegram.ui.Views.SettingsSectionLayout; import java.util.ArrayList; import java.util.HashMap; @@ -597,15 +598,13 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen @Override public View getSectionHeaderView(int section, View convertView, ViewGroup parent) { if (convertView == null) { - LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - convertView = li.inflate(R.layout.settings_section_layout, parent, false); + convertView = new SettingsSectionLayout(mContext); convertView.setBackgroundColor(0xffffffff); } - TextView textView = (TextView)convertView.findViewById(R.id.settings_section_text); if (searching && searchWas) { - textView.setText(LocaleController.getString("AllContacts", R.string.AllContacts)); + ((SettingsSectionLayout) convertView).setText(LocaleController.getString("AllContacts", R.string.AllContacts)); } else { - textView.setText(ContactsController.getInstance().sortedUsersSectionsArray.get(section)); + ((SettingsSectionLayout) convertView).setText(ContactsController.getInstance().sortedUsersSectionsArray.get(section)); } return convertView; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java index ac3dfe5f..972f87c4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java @@ -38,6 +38,7 @@ import org.telegram.ui.Views.BackupImageView; import org.telegram.ui.Views.ActionBar.BaseFragment; import org.telegram.ui.Views.PinnedHeaderListView; import org.telegram.ui.Views.SectionedBaseAdapter; +import org.telegram.ui.Views.SettingsSectionLayout; import java.util.ArrayList; import java.util.concurrent.Semaphore; @@ -420,12 +421,10 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati @Override public View getSectionHeaderView(int section, View convertView, ViewGroup parent) { if (convertView == null) { - LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - convertView = li.inflate(R.layout.settings_section_layout, parent, false); + convertView = new SettingsSectionLayout(mContext); convertView.setBackgroundColor(0xffffffff); } - TextView textView = (TextView)convertView.findViewById(R.id.settings_section_text); - textView.setText(LocaleController.formatPluralString("Members", selectedContacts.size()).toUpperCase()); + ((SettingsSectionLayout) convertView).setText(LocaleController.formatPluralString("Members", selectedContacts.size()).toUpperCase()); return convertView; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MessagesActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/MessagesActivity.java index 9471d2fb..c65d8152 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/MessagesActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/MessagesActivity.java @@ -12,6 +12,7 @@ import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; +import android.text.Html; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; @@ -35,13 +36,14 @@ import org.telegram.android.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; -import org.telegram.ui.Adapters.BaseFragmentAdapter; +import org.telegram.ui.Adapters.BaseContactsSearchAdapter; import org.telegram.ui.Cells.ChatOrUserCell; import org.telegram.ui.Cells.DialogCell; import org.telegram.ui.Views.ActionBar.ActionBarLayer; import org.telegram.ui.Views.ActionBar.ActionBarMenu; import org.telegram.ui.Views.ActionBar.ActionBarMenuItem; import org.telegram.ui.Views.ActionBar.BaseFragment; +import org.telegram.ui.Views.SettingsSectionLayout; import java.util.ArrayList; import java.util.Timer; @@ -64,10 +66,6 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter private int activityToken = (int)(Utilities.random.nextDouble() * Integer.MAX_VALUE); private long selectedDialog; - private Timer searchTimer; - public ArrayList searchResult; - public ArrayList searchResultNames; - private MessagesActivityDelegate delegate; private long openedDialogId = 0; @@ -144,7 +142,6 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter @Override public void onSearchCollapse() { - searchDialogs(null); searching = false; searchWas = false; if (messagesListView != null) { @@ -152,14 +149,16 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter searchEmptyView.setVisibility(View.GONE); } if (messagesListViewAdapter != null) { - messagesListViewAdapter.notifyDataSetChanged(); + messagesListViewAdapter.searchDialogs(null); } } @Override public void onTextChanged(EditText editText) { String text = editText.getText().toString(); - searchDialogs(text); + if (messagesListViewAdapter != null) { + messagesListViewAdapter.searchDialogs(text); + } if (text.length() != 0) { searchWas = true; if (messagesListViewAdapter != null) { @@ -231,10 +230,6 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter messagesListView = (ListView)fragmentView.findViewById(R.id.messages_list_view); messagesListView.setAdapter(messagesListViewAdapter); - if (delegate == null && AndroidUtilities.isTablet()) { - messagesListView.setDivider(inflater.getContext().getResources().getDrawable(R.drawable.messages_list_divider2)); - messagesListView.setDividerHeight(1); - } progressView = fragmentView.findViewById(R.id.progressLayout); messagesListViewAdapter.notifyDataSetChanged(); @@ -277,38 +272,34 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter messagesListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView adapterView, View view, int i, long l) { - long dialog_id = 0; - if (searching && searchWas) { - if (i >= searchResult.size()) { - return; - } - TLObject obj = searchResult.get(i); - if (obj instanceof TLRPC.User) { - dialog_id = ((TLRPC.User) obj).id; - } else if (obj instanceof TLRPC.Chat) { - if (((TLRPC.Chat) obj).id > 0) { - dialog_id = -((TLRPC.Chat) obj).id; - } else { - dialog_id = AndroidUtilities.makeBroadcastId(((TLRPC.Chat) obj).id); - } - } else if (obj instanceof TLRPC.EncryptedChat) { - dialog_id = ((long)((TLRPC.EncryptedChat) obj).id) << 32; - } - } else { - if (serverOnly) { - if (i >= MessagesController.getInstance().dialogsServerOnly.size()) { - return; - } - TLRPC.TL_dialog dialog = MessagesController.getInstance().dialogsServerOnly.get(i); - dialog_id = dialog.id; - } else { - if (i >= MessagesController.getInstance().dialogs.size()) { - return; - } - TLRPC.TL_dialog dialog = MessagesController.getInstance().dialogs.get(i); - dialog_id = dialog.id; - } + if (messagesListViewAdapter == null) { + return; } + TLObject obj = messagesListViewAdapter.getItem(i); + if (obj == null) { + return; + } + long dialog_id = 0; + if (obj instanceof TLRPC.User) { + dialog_id = ((TLRPC.User) obj).id; + if (messagesListViewAdapter.isGlobalSearch(i)) { + ArrayList users = new ArrayList(); + users.add((TLRPC.User)obj); + MessagesController.getInstance().putUsers(users, false); + MessagesStorage.getInstance().putUsersAndChats(users, null, false, true); + } + } else if (obj instanceof TLRPC.Chat) { + if (((TLRPC.Chat) obj).id > 0) { + dialog_id = -((TLRPC.Chat) obj).id; + } else { + dialog_id = AndroidUtilities.makeBroadcastId(((TLRPC.Chat) obj).id); + } + } else if (obj instanceof TLRPC.EncryptedChat) { + dialog_id = ((long)((TLRPC.EncryptedChat) obj).id) << 32; + } else if (obj instanceof TLRPC.TL_dialog) { + dialog_id = ((TLRPC.TL_dialog) obj).id; + } + if (onlySelect) { didSelectResult(dialog_id, true, false); } else { @@ -497,7 +488,7 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter } else if (id == NotificationCenter.reloadSearchResults) { int token = (Integer)args[0]; if (token == activityToken) { - updateSearchResults((ArrayList)args[1], (ArrayList)args[2], (ArrayList)args[3]); + messagesListViewAdapter.updateSearchResults((ArrayList) args[1], (ArrayList) args[2], (ArrayList) args[3]); } } else if (id == NotificationCenter.appDidLogout) { dialogsLoaded = false; @@ -624,86 +615,113 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter } } - public void updateSearchResults(final ArrayList result, final ArrayList names, final ArrayList encUsers) { - AndroidUtilities.RunOnUIThread(new Runnable() { - @Override - public void run() { - for (TLObject obj : result) { - if (obj instanceof TLRPC.User) { - TLRPC.User user = (TLRPC.User) obj; - MessagesController.getInstance().putUser(user, true); - } else if (obj instanceof TLRPC.Chat) { - TLRPC.Chat chat = (TLRPC.Chat) obj; - MessagesController.getInstance().putChat(chat, true); - } else if (obj instanceof TLRPC.EncryptedChat) { - TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat) obj; - MessagesController.getInstance().putEncryptedChat(chat, true); - } - } - for (TLRPC.User user : encUsers) { - MessagesController.getInstance().putUser(user, true); - } - searchResult = result; - searchResultNames = names; - if (searching) { - messagesListViewAdapter.notifyDataSetChanged(); - } - } - }); - } + private class MessagesAdapter extends BaseContactsSearchAdapter { - public void searchDialogs(final String query) { - if (query == null) { - searchResult = null; - searchResultNames = null; - } else { - try { - if (searchTimer != null) { - searchTimer.cancel(); - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } - searchTimer = new Timer(); - searchTimer.schedule(new TimerTask() { - @Override - public void run() { - try { - searchTimer.cancel(); - searchTimer = null; - } catch (Exception e) { - FileLog.e("tmessages", e); - } - MessagesStorage.getInstance().searchDialogs(activityToken, query, !serverOnly); - } - }, 100, 300); - } - } - - private class MessagesAdapter extends BaseFragmentAdapter { private Context mContext; + private Timer searchTimer; + private ArrayList searchResult; + private ArrayList searchResultNames; public MessagesAdapter(Context context) { mContext = context; } + public void updateSearchResults(final ArrayList result, final ArrayList names, final ArrayList encUsers) { + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + for (TLObject obj : result) { + if (obj instanceof TLRPC.User) { + TLRPC.User user = (TLRPC.User) obj; + MessagesController.getInstance().putUser(user, true); + } else if (obj instanceof TLRPC.Chat) { + TLRPC.Chat chat = (TLRPC.Chat) obj; + MessagesController.getInstance().putChat(chat, true); + } else if (obj instanceof TLRPC.EncryptedChat) { + TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat) obj; + MessagesController.getInstance().putEncryptedChat(chat, true); + } + } + for (TLRPC.User user : encUsers) { + MessagesController.getInstance().putUser(user, true); + } + searchResult = result; + searchResultNames = names; + if (searching) { + messagesListViewAdapter.notifyDataSetChanged(); + } + } + }); + } + + public boolean isGlobalSearch(int i) { + if (searching && searchWas) { + int localCount = searchResult == null ? 0 : searchResult.size(); + int globalCount = globalSearch == null ? 0 : globalSearch.size(); + if (i >= 0 && i < localCount) { + return false; + } else if (i > localCount && i <= globalCount + localCount) { + return true; + } + } + return false; + } + + public void searchDialogs(final String query) { + if (query == null) { + searchResult = null; + searchResultNames = null; + queryServerSearch(null); + notifyDataSetChanged(); + } else { + try { + if (searchTimer != null) { + searchTimer.cancel(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + searchTimer = new Timer(); + searchTimer.schedule(new TimerTask() { + @Override + public void run() { + try { + searchTimer.cancel(); + searchTimer = null; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + MessagesStorage.getInstance().searchDialogs(activityToken, query, !serverOnly); + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + queryServerSearch(query); + } + }); + } + }, 200, 300); + } + } + @Override public boolean areAllItemsEnabled() { - return true; + return false; } @Override public boolean isEnabled(int i) { - return true; + return !(searching && searchWas) || i != (searchResult == null ? 0 : searchResult.size()); } @Override public int getCount() { if (searching && searchWas) { - if (searchResult == null) { - return 0; + int count = searchResult == null ? 0 : searchResult.size(); + int globalCount = globalSearch == null ? 0 : globalSearch.size(); + if (globalCount != 0) { + count += globalCount + 1; } - return searchResult.size(); + return count; } int count; if (serverOnly) { @@ -721,8 +739,28 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter } @Override - public Object getItem(int i) { - return null; + public TLObject getItem(int i) { + if (searching && searchWas) { + int localCount = searchResult == null ? 0 : searchResult.size(); + int globalCount = globalSearch == null ? 0 : globalSearch.size(); + if (i >= 0 && i < localCount) { + return searchResult.get(i); + } else if (i > localCount && i <= globalCount + localCount) { + return globalSearch.get(i - localCount - 1); + } + return null; + } + if (serverOnly) { + if (i < 0 || i >= MessagesController.getInstance().dialogsServerOnly.size()) { + return null; + } + return MessagesController.getInstance().dialogsServerOnly.get(i); + } else { + if (i < 0 || i >= MessagesController.getInstance().dialogs.size()) { + return null; + } + return MessagesController.getInstance().dialogs.get(i); + } } @Override @@ -732,30 +770,47 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter @Override public boolean hasStableIds() { - return false; + return true; } @Override public View getView(int i, View view, ViewGroup viewGroup) { if (searching && searchWas) { - if (view == null) { - view = new ChatOrUserCell(mContext); - } - TLRPC.User user = null; - TLRPC.Chat chat = null; - TLRPC.EncryptedChat encryptedChat = null; + if (i == (searchResult == null ? 0 : searchResult.size())) { + if (view == null) { + view = new SettingsSectionLayout(mContext); + ((SettingsSectionLayout) view).setText(LocaleController.getString("GlobalSearch", R.string.GlobalSearch)); + view.setPadding(AndroidUtilities.dp(11), 0, AndroidUtilities.dp(11), 0); + } + } else { + if (view == null) { + view = new ChatOrUserCell(mContext); + } + TLRPC.User user = null; + TLRPC.Chat chat = null; + TLRPC.EncryptedChat encryptedChat = null; - TLObject obj = searchResult.get(i); - if (obj instanceof TLRPC.User) { - user = MessagesController.getInstance().getUser(((TLRPC.User)obj).id); - } else if (obj instanceof TLRPC.Chat) { - chat = MessagesController.getInstance().getChat(((TLRPC.Chat) obj).id); - } else if (obj instanceof TLRPC.EncryptedChat) { - encryptedChat = MessagesController.getInstance().getEncryptedChat(((TLRPC.EncryptedChat) obj).id); - user = MessagesController.getInstance().getUser(encryptedChat.user_id); - } + ((ChatOrUserCell) view).useSeparator = (i != getCount() - 1 && i != searchResult.size() - 1); + TLObject obj = getItem(i); + if (obj instanceof TLRPC.User) { + user = MessagesController.getInstance().getUser(((TLRPC.User) obj).id); + if (user == null) { + user = (TLRPC.User)obj; + } + } else if (obj instanceof TLRPC.Chat) { + chat = MessagesController.getInstance().getChat(((TLRPC.Chat) obj).id); + } else if (obj instanceof TLRPC.EncryptedChat) { + encryptedChat = MessagesController.getInstance().getEncryptedChat(((TLRPC.EncryptedChat) obj).id); + user = MessagesController.getInstance().getUser(encryptedChat.user_id); + } - ((ChatOrUserCell)view).setData(user, chat, encryptedChat, searchResultNames.get(i), null); + CharSequence username = null; + if (i > searchResult.size() && user.username != null) { + username = Html.fromHtml(String.format("@%s%s", user.username.substring(0, lastFoundUsername.length()), user.username.substring(lastFoundUsername.length()))); + } + + ((ChatOrUserCell) view).setData(user, chat, encryptedChat, i < searchResult.size() ? searchResultNames.get(i) : null, username); + } return view; } @@ -771,6 +826,7 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter if (view == null) { view = new DialogCell(mContext); } + ((DialogCell) view).useSeparator = (i != getCount() - 1); if (serverOnly) { ((DialogCell)view).setDialog(MessagesController.getInstance().dialogsServerOnly.get(i)); } else { @@ -791,12 +847,10 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter @Override public int getItemViewType(int i) { if (searching && searchWas) { - TLObject obj = searchResult.get(i); - if (obj instanceof TLRPC.User || obj instanceof TLRPC.EncryptedChat) { - return 2; - } else { + if (i == (searchResult == null ? 0 : searchResult.size())) { return 3; } + return 2; } if (serverOnly && i == MessagesController.getInstance().dialogsServerOnly.size() || !serverOnly && i == MessagesController.getInstance().dialogs.size()) { return 1; @@ -812,7 +866,7 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter @Override public boolean isEmpty() { if (searching && searchWas) { - return searchResult == null || searchResult.size() == 0; + return (searchResult == null || searchResult.size() == 0) && (globalSearch == null || globalSearch.isEmpty()); } if (MessagesController.getInstance().loadingDialogs && MessagesController.getInstance().dialogs.isEmpty()) { return false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index 635ed904..a1178e16 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -2140,7 +2140,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat float ai = -1; if (System.currentTimeMillis() - animationStartTime < animationDuration) { ai = interpolator.getInterpolation((float)(System.currentTimeMillis() - animationStartTime) / animationDuration); - if (ai >= 0.999f) { + if (ai >= 0.95f) { ai = -1; } } @@ -2221,7 +2221,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat int height = (int) (bitmapHeight * scale); centerImage.setImageCoords(-width / 2, -height / 2, width, height); - centerImage.draw(canvas, -width / 2, -height / 2, width, height); + centerImage.draw(canvas); } if (scale >= 1.0f) { @@ -2252,7 +2252,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat int height = (int) (bitmapHeight * scale); sideImage.setImageCoords(-width / 2, -height / 2, width, height); - sideImage.draw(canvas, -width / 2, -height / 2, width, height); + sideImage.draw(canvas); } } else { changingPage = false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SecretPhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/SecretPhotoViewer.java index 3dd8e29d..a0164a47 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SecretPhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SecretPhotoViewer.java @@ -365,7 +365,7 @@ public class SecretPhotoViewer implements NotificationCenter.NotificationCenterD int height = (int) (bitmapHeight * scale); centerImage.setImageCoords(-width / 2, -height / 2, width, height); - centerImage.draw(canvas, -width / 2, -height / 2, width, height); + centerImage.draw(canvas); } canvas.restore(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java index daa9f6de..fdcc3dd5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java @@ -60,6 +60,7 @@ import org.telegram.ui.Views.AvatarUpdater; import org.telegram.ui.Views.BackupImageView; import org.telegram.ui.Views.ActionBar.BaseFragment; import org.telegram.ui.Views.NumberPicker; +import org.telegram.ui.Views.SettingsSectionLayout; import java.io.File; import java.util.ArrayList; @@ -831,22 +832,20 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter return view; } else if (type == 1) { if (view == null) { - LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - view = li.inflate(R.layout.settings_section_layout, viewGroup, false); + view = new SettingsSectionLayout(mContext); } - TextView textView = (TextView)view.findViewById(R.id.settings_section_text); if (i == numberSectionRow) { - textView.setText(LocaleController.getString("Info", R.string.Info)); + ((SettingsSectionLayout) view).setText(LocaleController.getString("Info", R.string.Info)); } else if (i == settingsSectionRow) { - textView.setText(LocaleController.getString("SETTINGS", R.string.SETTINGS)); + ((SettingsSectionLayout) view).setText(LocaleController.getString("SETTINGS", R.string.SETTINGS)); } else if (i == supportSectionRow) { - textView.setText(LocaleController.getString("Support", R.string.Support)); + ((SettingsSectionLayout) view).setText(LocaleController.getString("Support", R.string.Support)); } else if (i == messagesSectionRow) { - textView.setText(LocaleController.getString("MessagesSettings", R.string.MessagesSettings)); + ((SettingsSectionLayout) view).setText(LocaleController.getString("MessagesSettings", R.string.MessagesSettings)); } else if (i == mediaDownloadSection) { - textView.setText(LocaleController.getString("AutomaticMediaDownload", R.string.AutomaticMediaDownload)); + ((SettingsSectionLayout) view).setText(LocaleController.getString("AutomaticMediaDownload", R.string.AutomaticMediaDownload)); } else if (i == contactsSectionRow) { - textView.setText(LocaleController.getString("Contacts", R.string.Contacts).toUpperCase()); + ((SettingsSectionLayout) view).setText(LocaleController.getString("Contacts", R.string.Contacts).toUpperCase()); } } else if (type == 2) { if (view == null) { @@ -971,7 +970,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter if (user != null && user.phone != null && user.phone.length() != 0) { detailTextView.setText(PhoneFormat.getInstance().format("+" + user.phone)); } else { - detailTextView.setText(LocaleController.getString("Unknown", R.string.Unknown)); + detailTextView.setText(LocaleController.getString("NumberUnknown", R.string.NumberUnknown)); } divider.setVisibility(View.VISIBLE); } else if (i == textSizeRow) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsBlockedUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsBlockedUsersActivity.java index b2e169a6..49f3f879 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsBlockedUsersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsBlockedUsersActivity.java @@ -249,7 +249,7 @@ public class SettingsBlockedUsersActivity extends BaseFragment implements Notifi ((ChatOrUserCell)view).useSeparator = true; } TLRPC.User user = MessagesController.getInstance().getUser(MessagesController.getInstance().blockedUsers.get(i)); - ((ChatOrUserCell)view).setData(user, null, null, null, user.phone != null && user.phone.length() != 0 ? PhoneFormat.getInstance().format("+" + user.phone) : LocaleController.getString("Unknown", R.string.Unknown)); + ((ChatOrUserCell)view).setData(user, null, null, null, user.phone != null && user.phone.length() != 0 ? PhoneFormat.getInstance().format("+" + user.phone) : LocaleController.getString("NumberUnknown", R.string.NumberUnknown)); } else if (type == 1) { if (view == null) { LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeNameActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeNameActivity.java index 86557b08..2d616aff 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeNameActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeNameActivity.java @@ -10,6 +10,9 @@ package org.telegram.ui; import android.app.Activity; import android.content.SharedPreferences; +import android.text.InputType; +import android.util.TypedValue; +import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -17,6 +20,7 @@ import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.widget.Button; import android.widget.EditText; +import android.widget.LinearLayout; import android.widget.TextView; import org.telegram.android.AndroidUtilities; @@ -30,6 +34,7 @@ import org.telegram.messenger.R; import org.telegram.messenger.RPCRequest; import org.telegram.messenger.UserConfig; import org.telegram.ui.Views.ActionBar.BaseFragment; +import org.telegram.ui.Views.SettingsSectionLayout; public class SettingsChangeNameActivity extends BaseFragment { private EditText firstNameField; @@ -63,14 +68,31 @@ public class SettingsChangeNameActivity extends BaseFragment { TextView textView = (TextView)doneButton.findViewById(R.id.done_button_text); textView.setText(LocaleController.getString("Done", R.string.Done).toUpperCase()); - fragmentView = inflater.inflate(R.layout.settings_change_name_layout, container, false); - TLRPC.User user = MessagesController.getInstance().getUser(UserConfig.getClientUserId()); if (user == null) { user = UserConfig.getCurrentUser(); } - firstNameField = (EditText)fragmentView.findViewById(R.id.first_name_field); + fragmentView = new LinearLayout(inflater.getContext()); + fragmentView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + fragmentView.setPadding(AndroidUtilities.dp(16), AndroidUtilities.dp(8), AndroidUtilities.dp(16), 0); + ((LinearLayout) fragmentView).setOrientation(LinearLayout.VERTICAL); + + SettingsSectionLayout settingsSectionLayout = new SettingsSectionLayout(inflater.getContext()); + ((LinearLayout) fragmentView).addView(settingsSectionLayout); + settingsSectionLayout.setText(LocaleController.getString("YourFirstNameAndLastName", R.string.YourFirstNameAndLastName).toUpperCase()); + + firstNameField = new EditText(inflater.getContext()); + firstNameField.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 19); + firstNameField.setHintTextColor(0xffa3a3a3); + firstNameField.setTextColor(0xff000000); + firstNameField.setPadding(AndroidUtilities.dp(15), 0, AndroidUtilities.dp(15), AndroidUtilities.dp(15)); + firstNameField.setMaxLines(1); + firstNameField.setLines(1); + firstNameField.setSingleLine(true); + firstNameField.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + firstNameField.setInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT); + firstNameField.setImeOptions(EditorInfo.IME_ACTION_NEXT); firstNameField.setHint(LocaleController.getString("FirstName", R.string.FirstName)); firstNameField.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override @@ -83,7 +105,25 @@ public class SettingsChangeNameActivity extends BaseFragment { return false; } }); - lastNameField = (EditText)fragmentView.findViewById(R.id.last_name_field); + AndroidUtilities.clearCursorDrawable(firstNameField); + ((LinearLayout) fragmentView).addView(firstNameField); + LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)firstNameField.getLayoutParams(); + layoutParams.topMargin = AndroidUtilities.dp(15); + layoutParams.width = LinearLayout.LayoutParams.MATCH_PARENT; + layoutParams.height = LinearLayout.LayoutParams.WRAP_CONTENT; + firstNameField.setLayoutParams(layoutParams); + + lastNameField = new EditText(inflater.getContext()); + lastNameField.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 19); + lastNameField.setHintTextColor(0xffa3a3a3); + lastNameField.setTextColor(0xff000000); + lastNameField.setPadding(AndroidUtilities.dp(15), 0, AndroidUtilities.dp(15), AndroidUtilities.dp(15)); + lastNameField.setMaxLines(1); + lastNameField.setLines(1); + lastNameField.setSingleLine(true); + lastNameField.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + lastNameField.setInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT); + lastNameField.setImeOptions(EditorInfo.IME_ACTION_DONE); lastNameField.setHint(LocaleController.getString("LastName", R.string.LastName)); lastNameField.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override @@ -95,15 +135,19 @@ public class SettingsChangeNameActivity extends BaseFragment { return false; } }); + AndroidUtilities.clearCursorDrawable(lastNameField); + ((LinearLayout) fragmentView).addView(lastNameField); + layoutParams = (LinearLayout.LayoutParams)lastNameField.getLayoutParams(); + layoutParams.topMargin = AndroidUtilities.dp(10); + layoutParams.width = LinearLayout.LayoutParams.MATCH_PARENT; + layoutParams.height = LinearLayout.LayoutParams.WRAP_CONTENT; + lastNameField.setLayoutParams(layoutParams); if (user != null) { firstNameField.setText(user.first_name); firstNameField.setSelection(firstNameField.length()); lastNameField.setText(user.last_name); } - - TextView headerLabel = (TextView)fragmentView.findViewById(R.id.settings_section_text); - headerLabel.setText(LocaleController.getString("YourFirstNameAndLastName", R.string.YourFirstNameAndLastName)); } else { ViewGroup parent = (ViewGroup)fragmentView.getParent(); if (parent != null) { @@ -129,9 +173,14 @@ public class SettingsChangeNameActivity extends BaseFragment { if (currentUser == null || lastNameField.getText() == null || firstNameField.getText() == null) { return; } + String newFirst = firstNameField.getText().toString(); + String newLast = lastNameField.getText().toString(); + if (currentUser.first_name != null && currentUser.first_name.equals(newFirst) && currentUser.last_name != null && currentUser.last_name.equals(newLast)) { + return; + } TLRPC.TL_account_updateProfile req = new TLRPC.TL_account_updateProfile(); - currentUser.first_name = req.first_name = firstNameField.getText().toString(); - currentUser.last_name = req.last_name = lastNameField.getText().toString(); + currentUser.first_name = req.first_name = newFirst; + currentUser.last_name = req.last_name = newLast; TLRPC.User user = MessagesController.getInstance().getUser(UserConfig.getClientUserId()); if (user != null) { user.first_name = req.first_name; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java index ca1e855b..bf01f63f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java @@ -13,6 +13,12 @@ import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.SharedPreferences; +import android.text.Editable; +import android.text.Html; +import android.text.InputType; +import android.text.TextWatcher; +import android.util.TypedValue; +import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -20,6 +26,7 @@ import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.widget.Button; import android.widget.EditText; +import android.widget.LinearLayout; import android.widget.TextView; import org.telegram.android.AndroidUtilities; @@ -35,13 +42,19 @@ import org.telegram.messenger.TLObject; import org.telegram.messenger.TLRPC; import org.telegram.messenger.UserConfig; import org.telegram.ui.Views.ActionBar.BaseFragment; +import org.telegram.ui.Views.SettingsSectionLayout; import java.util.ArrayList; public class SettingsChangeUsernameActivity extends BaseFragment { + private EditText firstNameField; - private View headerLabelView; private View doneButton; + private TextView checkTextView; + private long checkReqId = 0; + private String lastCheckName = null; + private Runnable checkRunnable = null; + private boolean lastNameAvailable = false; @Override public View createView(LayoutInflater inflater, ViewGroup container) { @@ -68,18 +81,37 @@ public class SettingsChangeUsernameActivity extends BaseFragment { TextView textView = (TextView)doneButton.findViewById(R.id.done_button_text); textView.setText(LocaleController.getString("Done", R.string.Done).toUpperCase()); - fragmentView = inflater.inflate(R.layout.chat_profile_change_name_layout, container, false); - TLRPC.User user = MessagesController.getInstance().getUser(UserConfig.getClientUserId()); if (user == null) { user = UserConfig.getCurrentUser(); } - firstNameField = (EditText)fragmentView.findViewById(R.id.first_name_field); + fragmentView = new LinearLayout(inflater.getContext()); + fragmentView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + fragmentView.setPadding(AndroidUtilities.dp(16), AndroidUtilities.dp(8), AndroidUtilities.dp(16), 0); + ((LinearLayout) fragmentView).setOrientation(LinearLayout.VERTICAL); + + SettingsSectionLayout settingsSectionLayout = new SettingsSectionLayout(inflater.getContext()); + ((LinearLayout) fragmentView).addView(settingsSectionLayout); + settingsSectionLayout.setText(LocaleController.getString("Username", R.string.Username).toUpperCase()); + + firstNameField = new EditText(inflater.getContext()); + firstNameField.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 19); + firstNameField.setHintTextColor(0xffa3a3a3); + firstNameField.setTextColor(0xff000000); + firstNameField.setPadding(AndroidUtilities.dp(15), 0, AndroidUtilities.dp(15), AndroidUtilities.dp(15)); + firstNameField.setMaxLines(1); + firstNameField.setLines(1); + firstNameField.setSingleLine(true); + firstNameField.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + firstNameField.setInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT); + firstNameField.setImeOptions(EditorInfo.IME_ACTION_DONE); + firstNameField.setHint(LocaleController.getString("UsernamePlaceholder", R.string.UsernamePlaceholder)); + AndroidUtilities.clearCursorDrawable(firstNameField); firstNameField.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_DONE) { + if (i == EditorInfo.IME_ACTION_DONE && doneButton != null) { doneButton.performClick(); return true; } @@ -87,13 +119,62 @@ public class SettingsChangeUsernameActivity extends BaseFragment { } }); + ((LinearLayout) fragmentView).addView(firstNameField); + LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)firstNameField.getLayoutParams(); + layoutParams.topMargin = AndroidUtilities.dp(15); + layoutParams.width = LinearLayout.LayoutParams.MATCH_PARENT; + layoutParams.height = LinearLayout.LayoutParams.WRAP_CONTENT; + firstNameField.setLayoutParams(layoutParams); + if (user != null && user.username != null && user.username.length() > 0) { firstNameField.setText(user.username); firstNameField.setSelection(firstNameField.length()); } - TextView headerLabel = (TextView)fragmentView.findViewById(R.id.settings_section_text); - headerLabel.setText(LocaleController.getString("Username", R.string.Username).toUpperCase()); + checkTextView = new TextView(inflater.getContext()); + checkTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + checkTextView.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), 0); + checkTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + ((LinearLayout) fragmentView).addView(checkTextView); + layoutParams = (LinearLayout.LayoutParams)checkTextView.getLayoutParams(); + layoutParams.topMargin = AndroidUtilities.dp(12); + layoutParams.width = LinearLayout.LayoutParams.WRAP_CONTENT; + layoutParams.height = LinearLayout.LayoutParams.WRAP_CONTENT; + layoutParams.gravity = LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT; + checkTextView.setLayoutParams(layoutParams); + + TextView helpTextView = new TextView(inflater.getContext()); + helpTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + helpTextView.setTextColor(0xff6d6d72); + helpTextView.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), 0); + helpTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + helpTextView.setText(Html.fromHtml(LocaleController.getString("UsernameHelp", R.string.UsernameHelp))); + ((LinearLayout) fragmentView).addView(helpTextView); + layoutParams = (LinearLayout.LayoutParams)helpTextView.getLayoutParams(); + layoutParams.topMargin = AndroidUtilities.dp(10); + layoutParams.width = LinearLayout.LayoutParams.WRAP_CONTENT; + layoutParams.height = LinearLayout.LayoutParams.WRAP_CONTENT; + layoutParams.gravity = LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT; + helpTextView.setLayoutParams(layoutParams); + + firstNameField.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { + + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { + checkUserName(firstNameField.getText().toString(), false); + } + + @Override + public void afterTextChanged(Editable editable) { + + } + }); + + checkTextView.setVisibility(View.GONE); } else { ViewGroup parent = (ViewGroup)fragmentView.getParent(); if (parent != null) { @@ -128,7 +209,118 @@ public class SettingsChangeUsernameActivity extends BaseFragment { showAlertDialog(builder); } + private boolean checkUserName(final String name, boolean alert) { + if (name != null && name.length() > 0) { + checkTextView.setVisibility(View.VISIBLE); + } else { + checkTextView.setVisibility(View.GONE); + } + if (alert && name.length() == 0) { + return true; + } + if (checkRunnable != null) { + AndroidUtilities.CancelRunOnUIThread(checkRunnable); + checkRunnable = null; + lastCheckName = null; + if (checkReqId != 0) { + ConnectionsManager.getInstance().cancelRpc(checkReqId, true); + } + } + lastNameAvailable = false; + if (name != null) { + for (int a = 0; a < name.length(); a++) { + char ch = name.charAt(a); + if (a == 0 && ch >= '0' && ch <= '9') { + if (alert) { + showErrorAlert(LocaleController.getString("UsernameInvalidStartNumber", R.string.UsernameInvalidStartNumber)); + } else { + checkTextView.setText(LocaleController.getString("UsernameInvalidStartNumber", R.string.UsernameInvalidStartNumber)); + checkTextView.setTextColor(0xffcf3030); + } + return false; + } + if (!(ch >= '0' && ch <= '9' || ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || a == '_')) { + if (alert) { + showErrorAlert(LocaleController.getString("UsernameInvalid", R.string.UsernameInvalid)); + } else { + checkTextView.setText(LocaleController.getString("UsernameInvalid", R.string.UsernameInvalid)); + checkTextView.setTextColor(0xffcf3030); + } + return false; + } + } + } + if (name == null || name.length() < 5) { + if (alert) { + showErrorAlert(LocaleController.getString("UsernameInvalidShort", R.string.UsernameInvalidShort)); + } else { + checkTextView.setText(LocaleController.getString("UsernameInvalidShort", R.string.UsernameInvalidShort)); + checkTextView.setTextColor(0xffcf3030); + } + return false; + } + if (name.length() > 32) { + if (alert) { + showErrorAlert(LocaleController.getString("UsernameInvalidLong", R.string.UsernameInvalidLong)); + } else { + checkTextView.setText(LocaleController.getString("UsernameInvalidLong", R.string.UsernameInvalidLong)); + checkTextView.setTextColor(0xffcf3030); + } + return false; + } + + if (!alert) { + String currentName = UserConfig.getCurrentUser().username; + if (currentName == null) { + currentName = ""; + } + if (name.equals(currentName)) { + checkTextView.setText(LocaleController.formatString("UsernameAvailable", R.string.UsernameAvailable, name)); + checkTextView.setTextColor(0xff26972c); + return true; + } + + checkTextView.setText(LocaleController.getString("UsernameChecking", R.string.UsernameChecking)); + checkTextView.setTextColor(0xff6d6d72); + lastCheckName = name; + checkRunnable = new Runnable() { + @Override + public void run() { + TLRPC.TL_account_checkUsername req = new TLRPC.TL_account_checkUsername(); + req.username = name; + checkReqId = ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + checkReqId = 0; + if (lastCheckName != null && lastCheckName.equals(name)) { + if (error == null && response instanceof TLRPC.TL_boolTrue) { + checkTextView.setText(LocaleController.formatString("UsernameAvailable", R.string.UsernameAvailable, name)); + checkTextView.setTextColor(0xff26972c); + lastNameAvailable = true; + } else { + checkTextView.setText(LocaleController.getString("UsernameInUse", R.string.UsernameInUse)); + checkTextView.setTextColor(0xffcf3030); + lastNameAvailable = false; + } + } + } + }); + } + }, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors); + } + }; + AndroidUtilities.RunOnUIThread(checkRunnable, 300); + } + return true; + } + private void saveName() { + if (!checkUserName(firstNameField.getText().toString(), true)) { + return; + } TLRPC.User user = UserConfig.getCurrentUser(); if (getParentActivity() == null || user == null) { return; @@ -142,10 +334,6 @@ public class SettingsChangeUsernameActivity extends BaseFragment { finishFragment(); return; } - if (newName.length() > 32 || newName.length() > 0 && newName.length() < 5) { - showErrorAlert("USERNAME_INVALID"); - return; - } final ProgressDialog progressDialog = new ProgressDialog(getParentActivity()); progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsNotificationsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsNotificationsActivity.java index 7d7c41ae..0e2f2c0b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsNotificationsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsNotificationsActivity.java @@ -42,6 +42,7 @@ import org.telegram.ui.Adapters.BaseFragmentAdapter; import org.telegram.ui.Views.ActionBar.ActionBarLayer; import org.telegram.ui.Views.ActionBar.BaseFragment; import org.telegram.ui.Views.ColorPickerView; +import org.telegram.ui.Views.SettingsSectionLayout; public class SettingsNotificationsActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { private ListView listView; @@ -541,22 +542,20 @@ public class SettingsNotificationsActivity extends BaseFragment implements Notif int type = getItemViewType(i); if (type == 0) { if (view == null) { - LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - view = li.inflate(R.layout.settings_section_layout, viewGroup, false); + view = new SettingsSectionLayout(mContext); } - TextView textView = (TextView)view.findViewById(R.id.settings_section_text); if (i == messageSectionRow) { - textView.setText(LocaleController.getString("MessageNotifications", R.string.MessageNotifications)); + ((SettingsSectionLayout) view).setText(LocaleController.getString("MessageNotifications", R.string.MessageNotifications)); } else if (i == groupSectionRow) { - textView.setText(LocaleController.getString("GroupNotifications", R.string.GroupNotifications)); + ((SettingsSectionLayout) view).setText(LocaleController.getString("GroupNotifications", R.string.GroupNotifications)); } else if (i == inappSectionRow) { - textView.setText(LocaleController.getString("InAppNotifications", R.string.InAppNotifications)); + ((SettingsSectionLayout) view).setText(LocaleController.getString("InAppNotifications", R.string.InAppNotifications)); } else if (i == eventsSectionRow) { - textView.setText(LocaleController.getString("Events", R.string.Events)); + ((SettingsSectionLayout) view).setText(LocaleController.getString("Events", R.string.Events)); } else if (i == otherSectionRow) { - textView.setText(LocaleController.getString("PhoneOther", R.string.PhoneOther)); + ((SettingsSectionLayout) view).setText(LocaleController.getString("PhoneOther", R.string.PhoneOther)); } else if (i == resetSectionRow) { - textView.setText(LocaleController.getString("Reset", R.string.Reset)); + ((SettingsSectionLayout) view).setText(LocaleController.getString("Reset", R.string.Reset)); } } if (type == 1) { if (view == null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java index 84c53c1a..236ce54b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java @@ -41,6 +41,7 @@ import org.telegram.ui.Views.ActionBar.ActionBarMenuItem; import org.telegram.ui.Views.BackupImageView; import org.telegram.ui.Views.ActionBar.BaseFragment; import org.telegram.ui.Views.IdenticonView; +import org.telegram.ui.Views.SettingsSectionLayout; import java.util.ArrayList; @@ -539,16 +540,14 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen return view; } else if (type == 1) { if (view == null) { - LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - view = li.inflate(R.layout.settings_section_layout, viewGroup, false); + view = new SettingsSectionLayout(mContext); } - TextView textView = (TextView)view.findViewById(R.id.settings_section_text); if (i == phoneSectionRow) { - textView.setText(LocaleController.getString("Info", R.string.Info)); + ((SettingsSectionLayout) view).setText(LocaleController.getString("Info", R.string.Info)); } else if (i == settingsSectionRow) { - textView.setText(LocaleController.getString("SETTINGS", R.string.SETTINGS)); + ((SettingsSectionLayout) view).setText(LocaleController.getString("SETTINGS", R.string.SETTINGS)); } else if (i == sharedMediaSectionRow) { - textView.setText(LocaleController.getString("SHAREDMEDIA", R.string.SHAREDMEDIA)); + ((SettingsSectionLayout) view).setText(LocaleController.getString("SHAREDMEDIA", R.string.SHAREDMEDIA)); } } else if (type == 2) { final TLRPC.User user = MessagesController.getInstance().getUser(user_id); @@ -621,7 +620,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen if (user.phone != null && user.phone.length() != 0) { textView.setText(PhoneFormat.getInstance().format("+" + user.phone)); } else { - textView.setText(LocaleController.getString("Unknown", R.string.Unknown)); + textView.setText(LocaleController.getString("NumberUnknown", R.string.NumberUnknown)); } divider.setVisibility(usernameRow != -1 ? View.VISIBLE : View.INVISIBLE); detailTextView.setText(LocaleController.getString("PhoneMobile", R.string.PhoneMobile)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/BackupImageView.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/BackupImageView.java index 529f715c..b584dcda 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/BackupImageView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/BackupImageView.java @@ -91,6 +91,6 @@ public class BackupImageView extends View { @Override protected void onDraw(Canvas canvas) { imageReceiver.setImageCoords(0, 0, getWidth(), getHeight()); - imageReceiver.draw(canvas, 0, 0, getWidth(), getHeight()); + imageReceiver.draw(canvas); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/SettingsSectionLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/SettingsSectionLayout.java new file mode 100644 index 00000000..f7bab4ec --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/SettingsSectionLayout.java @@ -0,0 +1,82 @@ +/* + * This is the source code of Telegram for Android v. 1.7.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2014. + */ + +package org.telegram.ui.Views; + +import android.content.Context; +import android.graphics.Typeface; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.telegram.android.AndroidUtilities; +import org.telegram.android.LocaleController; + +public class SettingsSectionLayout extends LinearLayout { + + private TextView textView; + + private void init() { + setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + setOrientation(LinearLayout.VERTICAL); + + textView = new TextView(getContext()); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)); + textView.setTextColor(0xff3b84c0); + addView(textView); + LayoutParams layoutParams = (LayoutParams)textView.getLayoutParams(); + layoutParams.width = LayoutParams.WRAP_CONTENT; + layoutParams.height = LayoutParams.WRAP_CONTENT; + layoutParams.leftMargin = AndroidUtilities.dp(8); + layoutParams.rightMargin = AndroidUtilities.dp(8); + layoutParams.topMargin = AndroidUtilities.dp(6); + layoutParams.bottomMargin = AndroidUtilities.dp(4); + if (LocaleController.isRTL) { + textView.setGravity(Gravity.RIGHT); + layoutParams.gravity = Gravity.RIGHT; + } + textView.setLayoutParams(layoutParams); + + View view = new View(getContext()); + view.setBackgroundColor(0xff6caae4); + addView(view); + layoutParams = (LayoutParams)view.getLayoutParams(); + layoutParams.weight = LayoutParams.MATCH_PARENT; + layoutParams.height = AndroidUtilities.dp(1); + view.setLayoutParams(layoutParams); + } + + public SettingsSectionLayout(Context context) { + super(context); + init(); + } + + public SettingsSectionLayout(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public SettingsSectionLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + public SettingsSectionLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(); + } + + public void setText(String text) { + textView.setText(text); + } +} diff --git a/TMessagesProj/src/main/res/drawable-hdpi/holo_textfield_activated_holo_light.9.png b/TMessagesProj/src/main/res/drawable-hdpi/textfield_activated.9.png similarity index 100% rename from TMessagesProj/src/main/res/drawable-hdpi/holo_textfield_activated_holo_light.9.png rename to TMessagesProj/src/main/res/drawable-hdpi/textfield_activated.9.png diff --git a/TMessagesProj/src/main/res/drawable-hdpi/holo_textfield_default_holo_light.9.png b/TMessagesProj/src/main/res/drawable-hdpi/textfield_default.9.png similarity index 100% rename from TMessagesProj/src/main/res/drawable-hdpi/holo_textfield_default_holo_light.9.png rename to TMessagesProj/src/main/res/drawable-hdpi/textfield_default.9.png diff --git a/TMessagesProj/src/main/res/drawable-hdpi/holo_textfield_disabled_focused_holo_light.9.png b/TMessagesProj/src/main/res/drawable-hdpi/textfield_disabled.9.png similarity index 100% rename from TMessagesProj/src/main/res/drawable-hdpi/holo_textfield_disabled_focused_holo_light.9.png rename to TMessagesProj/src/main/res/drawable-hdpi/textfield_disabled.9.png diff --git a/TMessagesProj/src/main/res/drawable-hdpi/holo_textfield_disabled_holo_light.9.png b/TMessagesProj/src/main/res/drawable-hdpi/textfield_disabled2.9.png similarity index 100% rename from TMessagesProj/src/main/res/drawable-hdpi/holo_textfield_disabled_holo_light.9.png rename to TMessagesProj/src/main/res/drawable-hdpi/textfield_disabled2.9.png diff --git a/TMessagesProj/src/main/res/drawable-hdpi/holo_textfield_focused_holo_light.9.png b/TMessagesProj/src/main/res/drawable-hdpi/textfield_focused.9.png similarity index 100% rename from TMessagesProj/src/main/res/drawable-hdpi/holo_textfield_focused_holo_light.9.png rename to TMessagesProj/src/main/res/drawable-hdpi/textfield_focused.9.png diff --git a/TMessagesProj/src/main/res/drawable-mdpi/holo_textfield_activated_holo_light.9.png b/TMessagesProj/src/main/res/drawable-mdpi/textfield_activated.9.png similarity index 100% rename from TMessagesProj/src/main/res/drawable-mdpi/holo_textfield_activated_holo_light.9.png rename to TMessagesProj/src/main/res/drawable-mdpi/textfield_activated.9.png diff --git a/TMessagesProj/src/main/res/drawable-mdpi/holo_textfield_default_holo_light.9.png b/TMessagesProj/src/main/res/drawable-mdpi/textfield_default.9.png similarity index 100% rename from TMessagesProj/src/main/res/drawable-mdpi/holo_textfield_default_holo_light.9.png rename to TMessagesProj/src/main/res/drawable-mdpi/textfield_default.9.png diff --git a/TMessagesProj/src/main/res/drawable-mdpi/holo_textfield_disabled_focused_holo_light.9.png b/TMessagesProj/src/main/res/drawable-mdpi/textfield_disabled.9.png similarity index 100% rename from TMessagesProj/src/main/res/drawable-mdpi/holo_textfield_disabled_focused_holo_light.9.png rename to TMessagesProj/src/main/res/drawable-mdpi/textfield_disabled.9.png diff --git a/TMessagesProj/src/main/res/drawable-mdpi/holo_textfield_disabled_holo_light.9.png b/TMessagesProj/src/main/res/drawable-mdpi/textfield_disabled2.9.png similarity index 100% rename from TMessagesProj/src/main/res/drawable-mdpi/holo_textfield_disabled_holo_light.9.png rename to TMessagesProj/src/main/res/drawable-mdpi/textfield_disabled2.9.png diff --git a/TMessagesProj/src/main/res/drawable-mdpi/holo_textfield_focused_holo_light.9.png b/TMessagesProj/src/main/res/drawable-mdpi/textfield_focused.9.png similarity index 100% rename from TMessagesProj/src/main/res/drawable-mdpi/holo_textfield_focused_holo_light.9.png rename to TMessagesProj/src/main/res/drawable-mdpi/textfield_focused.9.png diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/holo_textfield_activated_holo_light.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/textfield_activated.9.png similarity index 100% rename from TMessagesProj/src/main/res/drawable-xhdpi/holo_textfield_activated_holo_light.9.png rename to TMessagesProj/src/main/res/drawable-xhdpi/textfield_activated.9.png diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/holo_textfield_default_holo_light.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/textfield_default.9.png similarity index 100% rename from TMessagesProj/src/main/res/drawable-xhdpi/holo_textfield_default_holo_light.9.png rename to TMessagesProj/src/main/res/drawable-xhdpi/textfield_default.9.png diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/holo_textfield_disabled_focused_holo_light.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/textfield_disabled.9.png similarity index 100% rename from TMessagesProj/src/main/res/drawable-xhdpi/holo_textfield_disabled_focused_holo_light.9.png rename to TMessagesProj/src/main/res/drawable-xhdpi/textfield_disabled.9.png diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/holo_textfield_disabled_holo_light.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/textfield_disabled2.9.png similarity index 100% rename from TMessagesProj/src/main/res/drawable-xhdpi/holo_textfield_disabled_holo_light.9.png rename to TMessagesProj/src/main/res/drawable-xhdpi/textfield_disabled2.9.png diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/holo_textfield_focused_holo_light.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/textfield_focused.9.png similarity index 100% rename from TMessagesProj/src/main/res/drawable-xhdpi/holo_textfield_focused_holo_light.9.png rename to TMessagesProj/src/main/res/drawable-xhdpi/textfield_focused.9.png diff --git a/TMessagesProj/src/main/res/drawable/holo_edit_text_light.xml b/TMessagesProj/src/main/res/drawable/edit_text.xml similarity index 51% rename from TMessagesProj/src/main/res/drawable/holo_edit_text_light.xml rename to TMessagesProj/src/main/res/drawable/edit_text.xml index 65ab33c7..492bc906 100644 --- a/TMessagesProj/src/main/res/drawable/holo_edit_text_light.xml +++ b/TMessagesProj/src/main/res/drawable/edit_text.xml @@ -1,11 +1,11 @@ - - - - - - - + + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/layout-ar/chat_profile_change_name_layout.xml b/TMessagesProj/src/main/res/layout-ar/chat_profile_change_name_layout.xml deleted file mode 100644 index 0ace49c8..00000000 --- a/TMessagesProj/src/main/res/layout-ar/chat_profile_change_name_layout.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/layout-ar/messages_list.xml b/TMessagesProj/src/main/res/layout-ar/messages_list.xml index 535c825b..15d7d46a 100644 --- a/TMessagesProj/src/main/res/layout-ar/messages_list.xml +++ b/TMessagesProj/src/main/res/layout-ar/messages_list.xml @@ -11,8 +11,8 @@ android:layout_alignParentBottom="true" android:clipToPadding="false" android:fadingEdge="none" - android:divider="@drawable/messages_list_divider" - android:dividerHeight="1px" + android:divider="@null" + android:dividerHeight="0px" android:fadingEdgeLength="0dp" android:verticalScrollbarPosition="left"/> diff --git a/TMessagesProj/src/main/res/layout-ar/notification_layout.xml b/TMessagesProj/src/main/res/layout-ar/notification_layout.xml deleted file mode 100644 index 5b1d7ca6..00000000 --- a/TMessagesProj/src/main/res/layout-ar/notification_layout.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/TMessagesProj/src/main/res/layout-ar/settings_change_name_layout.xml b/TMessagesProj/src/main/res/layout-ar/settings_change_name_layout.xml deleted file mode 100644 index 8f51da6d..00000000 --- a/TMessagesProj/src/main/res/layout-ar/settings_change_name_layout.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/layout-ar/settings_section_layout.xml b/TMessagesProj/src/main/res/layout-ar/settings_section_layout.xml deleted file mode 100644 index 79793ba3..00000000 --- a/TMessagesProj/src/main/res/layout-ar/settings_section_layout.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/layout/chat_profile_change_name_layout.xml b/TMessagesProj/src/main/res/layout/chat_profile_change_name_layout.xml deleted file mode 100644 index 27a53366..00000000 --- a/TMessagesProj/src/main/res/layout/chat_profile_change_name_layout.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/layout/messages_list.xml b/TMessagesProj/src/main/res/layout/messages_list.xml index bd3eb600..1615aa8e 100644 --- a/TMessagesProj/src/main/res/layout/messages_list.xml +++ b/TMessagesProj/src/main/res/layout/messages_list.xml @@ -9,11 +9,10 @@ android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentBottom="true" - android:clipToPadding="false" android:fadingEdge="none" android:fadingEdgeLength="0dp" - android:divider="@drawable/messages_list_divider" - android:dividerHeight="1px" + android:divider="@null" + android:dividerHeight="0px" android:animationCache="false"/> - - - - - - - - - - - - - - - - - - diff --git a/TMessagesProj/src/main/res/layout/settings_change_name_layout.xml b/TMessagesProj/src/main/res/layout/settings_change_name_layout.xml deleted file mode 100644 index 6bdd8e59..00000000 --- a/TMessagesProj/src/main/res/layout/settings_change_name_layout.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/layout/settings_section_layout.xml b/TMessagesProj/src/main/res/layout/settings_section_layout.xml deleted file mode 100644 index a9b6d851..00000000 --- a/TMessagesProj/src/main/res/layout/settings_section_layout.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-ar/strings.xml b/TMessagesProj/src/main/res/values-ar/strings.xml index 846b80dd..8bbcb33a 100644 --- a/TMessagesProj/src/main/res/values-ar/strings.xml +++ b/TMessagesProj/src/main/res/values-ar/strings.xml @@ -51,9 +51,10 @@ حذف وخروج الاسم مخفي اختر محادثة + %1$s يستخدم إصدار قديم من تيليجرام، لذلك، الصور السرية ستظهر في وضع الموافقة.\n\nعندما يقوم %2$s بتحديث تيليجرام، الصور التي بها عداد دقيقة أو أقل ستعمل بطريقة \"الاستمرار بالضغط للإستعراض\"، وسيتم إخبارك عندما يلتقط المستقبل صورة من شاشته. قائمة الرسالة الجماعية - قائمة رسالة جماعية جديدة + رسالة جماعية جديدة أدخل اسم القائمة أنت قمت بإنشاء قائمة رسالة جماعية إضافة مستلم @@ -146,8 +147,8 @@ %1$s,\nتم تسجيل الدخول لحسابك من جهاز جديد يوم %2$s\n\nالجهاز: %3$s\nالموقع: %4$s\n\nإذا لم يكن أنت من سجل الدخول، يمكنك الذهاب للإعدادات ثم تسجيل الخروج من كافة الأجهزة الأخرى.\n\nشكرًا,\nفريق عمل تيليجرام %1$s قام بتغيير صورته الشخصية الرد - Reply to %1$s - Reply to %1$s + الرد على %1$s + الرد على %1$s %1$s %2$s اختر جهة اتصال @@ -160,7 +161,7 @@ آخر ظهور آخر ظهور قم بدعوة صديق - GLOBAL SEARCH + بحث شامل إرسال الرسالة إلى... أدخل اسم للمجموعة @@ -198,16 +199,19 @@ عداد التدمير الذاتي إيقاف هذه الصورة هي تصور لمفتاح التشفير لهذه المحادثة السرية مع ]]>%1$s]]>.
    ]]>إذا كانت مطابقة للصورة التي في جهاز ]]>%2$s]]>, فمحادثتكم آمنة ٢٠٠٪.
    ]]>للمزيد نرجو الذهاب إلى telegram.org
    - Unknown - INFO - الهاتف - Username - Your Username - Sorry, this username is already taken. - Sorry, this username is invalid. - A username must have at least 5 characters. - Sorry, a username can't start with a number. - You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.\n\nYou can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters. + غير معروف + معلومات + هاتف + اسم مستخدم + معرّفك + المعذرة، اسم المستخدم تم اختياره مسبقًا. + المعذرة، اسم المستخدم غير مقبول. + سم المستخدم يجب أن يتكوّن من ٥ حروف على الأقل. + اسم المستخدم يجب ألا يتخطى ٣٢ حرف كحد أقصى. + المعذرة، اسم المستخدم لا يمكن أن يبدأ برقم. + يمكنك اختيار اسم مستخدم في ]]>تيليجرام]]>. إذا قمت بذلك، سيستطيع الناس إيجادك باستخدام الاسم المستخدم والتواصل معك من دون معرفة رقمك.
    ]]>يمكنك استخدام ]]>حروف اللغة الإنجليزية]]>, ]]>وأرقامها]]> و كذلك الخط. لا بد من استخدام ]]>٥]]> حروف على الأقل.
    + جاري مراجعة اسم المستخدم... + %1$s متاح. تم تعيين كافة الإشعارات افتراضيا حجم نص الرسائل @@ -387,7 +391,7 @@ قوي مرتبط بالسحاب خصوصي - أسرع تطبيق مراسلة في العالم.]]>كما أنه مجاني و آمن. + أسرع تطبيق مراسلة في العالم. ]]>كما أنه مجاني و آمن. تيليجرام
    ]]> يوصل الرسائل أسرع من أي تطبيق آخر. تيليجرام
    ]]> مجاني للأبد. بدون أية إعلانات. وبدون رسوم إشتراك. تيليجرام
    ]]> يحمي الرسائل الخاصة بك من هجمات المخترقين. @@ -395,7 +399,7 @@ تيليجرام
    ]]> يمكنك الوصول إلى الرسائل الخاصة بك من أجهزة متعددة. تيليجرام]]> الرسائل مشفرة بشكل قوي وتستطيع تدمير ذاتها إبدأ المراسلة - + %1$d متصل %1$d متصل %1$d متصل @@ -432,42 +436,42 @@ من %1$d جهات اتصال من %1$d جهة اتصال من %1$d جهة اتصال - %1$d seconds - %1$d second - %1$d seconds - %1$d seconds - %1$d seconds - %1$d seconds - %1$d minutes - %1$d minute - %1$d minutes - %1$d minutes - %1$d minutes - %1$d minutes - %1$d hours - %1$d hour - %1$d hours - %1$d hours - %1$d hours - %1$d hours - %1$d days - %1$d day - %1$d days - %1$d days - %1$d days - %1$d days - %1$d weeks - %1$d week - %1$d weeks - %1$d weeks - %1$d weeks - %1$d weeks + %1$d ثانية + %1$d ثانية + %1$d ثانيتان + %1$d ثوانٍ + %1$d ثانية + %1$d ثانية + %1$d دقيقة + %1$d دقيقة + %1$d دقيقتان + %1$d دقائق + %1$d دقيقة + %1$d دقيقة + %1$d ساعة + %1$d ساعة + %1$d ساعتان + %1$d ساعات + %1$d ساعة + %1$d ساعة + %1$d يوم + %1$d يوم + %1$d يومان + %1$d أيام + %1$d يوم + %1$d يوم + %1$d أسبوع + %1$d أسبوع + %1$d أسبوعان + %1$d أسابيع + %1$d أسبوع + %1$d أسبوع - dd MMM + MMM dd dd.MM.yy dd.MM.yyyy - d MMMM - d MMMM yyyy + MMMM d + MMMM d, yyyy EEE HH:mm h:mm a diff --git a/TMessagesProj/src/main/res/values-de/strings.xml b/TMessagesProj/src/main/res/values-de/strings.xml index 2880d6f5..796e9938 100644 --- a/TMessagesProj/src/main/res/values-de/strings.xml +++ b/TMessagesProj/src/main/res/values-de/strings.xml @@ -51,6 +51,7 @@ Löschen und beenden Versteckter Name Chat auswählen + %1$s benutzt eine ältere Version von Telegram, sodass Fotos in Geheimen Chats im Kompatibilitätsmodus angezeigt werden.\n\nSobald %2$s Telegram aktualisiert, werden Fotos mit Timern von 1 Minute und kürzer per \"Tippen und Halten\" angezeigt. Du wirst benachrichtigt, sobald dein Chatpartner ein Bildschirmfoto macht. Broadcast Liste Neue Broadcast Liste @@ -160,7 +161,7 @@ zul. online zul. online Freunde einladen - GLOBAL SEARCH + GLOBALE SUCHE Sende Nachricht an… Gruppenname @@ -198,16 +199,19 @@ Selbstzerstörungs-Timer Aus Das ist eine Darstellung des Schlüssels für den Geheimen Chat mit ]]>%1$s]]>.
    ]]>Wenn dieses Bild auf ]]>%2$s\s]]>s Telefon genau so aussieht, ist euer Chat zu 200%% sicher.
    ]]>Erfahre mehr auf telegram.org
    - Unknown + Unbekannt INFO Telefon - Username - Your Username - Sorry, this username is already taken. - Sorry, this username is invalid. - A username must have at least 5 characters. - Sorry, a username can't start with a number. - You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.\n\nYou can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters. + Benutzername + Dein Benutzername + Leider ist dieser Benutzername vergeben. + Benutzername leider nicht erlaubt. + Ein Benutzername benötigt mindestens 5 Zeichen. + Ein Benutzername darf maximal 32 Zeichen haben. + Benutzernamen dürfen leider nicht mit einer Zahl anfangen. + Wähle einen Benutzernamen, wenn du von anderen bei]]>Telegram]]>gefunden werden willst – ohne, dass sie deine Nummer kennen müssen.
    ]]>Erlaubt sind ]]>a–z]]>, ]]>0–9]]> und Unterstriche. Die Mindestlänge beträgt ]]>5]]> Zeichen.
    + Prüfe Benutzername... + %1$s ist verfügbar. Alle Einstellungen für Mitteilungen zurücksetzen Textgröße für Nachrichten @@ -247,8 +251,8 @@ Sprache Bedenke bitte, dass der Telegram Support von einem ehrenamtlichen Team betreut wird. Wir versuchen so schnell wie möglich zu antworten, dies kann jedoch manchmal ein bisschen dauern.
    ]]>Bitte schau auch in den Fragen und Antworten ]]> nach. Dort findest du Antworten auf die meisten Fragen und wichtige Tipps zur Problembehandlung]]>.
    Frage einen Freiwilligen - Fragen und Antworten zu Telegram - https://telegram.org/faq + Fragen und Antworten + https://telegram.org/faq/ko Lokalisierung löschen? Falsche Sprachdatei Aktiviert @@ -432,36 +436,36 @@ von %1$d Kontakten von %1$d Kontakten von %1$d Kontakten - %1$d seconds - %1$d second - %1$d seconds - %1$d seconds - %1$d seconds - %1$d seconds - %1$d minutes - %1$d minute - %1$d minutes - %1$d minutes - %1$d minutes - %1$d minutes - %1$d hours - %1$d hour - %1$d hours - %1$d hours - %1$d hours - %1$d hours - %1$d days - %1$d day - %1$d days - %1$d days - %1$d days - %1$d days - %1$d weeks - %1$d week - %1$d weeks - %1$d weeks - %1$d weeks - %1$d weeks + %1$d Sekunden + %1$d Sekunde + %1$d Sekunden + %1$d Sekunden + %1$d Sekunden + %1$d Sekunden + %1$d Minuten + %1$d Minute + %1$d Minuten + %1$d Minuten + %1$d Minuten + %1$d Minuten + %1$d Stunden + %1$d Stunde + %1$d Stunden + %1$d Stunden + %1$d Stunden + %1$d Stunden + %1$d Tage + %1$d Tag + %1$d Tage + %1$d Tage + %1$d Tage + %1$d Tage + %1$d Wochen + %1$d Woche + %1$d Wochen + %1$d Wochen + %1$d Wochen + %1$d Wochen dd MMM dd.MM.yy diff --git a/TMessagesProj/src/main/res/values-es/strings.xml b/TMessagesProj/src/main/res/values-es/strings.xml index b1fc0208..87f41149 100644 --- a/TMessagesProj/src/main/res/values-es/strings.xml +++ b/TMessagesProj/src/main/res/values-es/strings.xml @@ -51,6 +51,7 @@ Eliminar y salir Nombre oculto Elige el chat + %1$s usa una versión antigua de Telegram, así que las fotos secretas serán mostradas en un modo de compatibilidad.\n\nCuando %2$s actualice Telegram, las fotos con autodestrucción de 1 minuto o menos funcionarán con el modo \'Mantén pulsado para ver\', y te notificaremos siempre que la otra parte haga una captura de pantalla. Lista de difusión Nueva difusión @@ -73,10 +74,10 @@ Tarjeta SD invisible - escribe... + escribiendo... Adjuntar - escribe... - escriben... + está escribiendo... + están escribiendo... ¿Tienes preguntas\nsobre Telegram? Hacer foto Galería @@ -160,7 +161,7 @@ últ. vez últ. vez el Invitar a amigos - GLOBAL SEARCH + BÚSQUEDA GLOBAL Enviar mensaje a... Nombre del grupo @@ -170,7 +171,7 @@ PON EL NOMBRE DEL GRUPO Fotos y vídeos - Información + Información FOTOS Y VÍDEOS AJUSTES Añadir miembro @@ -198,16 +199,19 @@ Autodestrucción Apagada Esta imagen es una visualización de la clave de cifrado para el chat secreto con ]]>%1$s]]>.
    ]]>Si esta imagen se ve igual en el teléfono de ]]>%2$s]]>, tu chat es seguro en un 200%%.
    ]]>Aprende más en telegram.org
    - Unknown - INFO + Desconocido + INFORMACIÓN Teléfono - Username - Your Username - Sorry, this username is already taken. - Sorry, this username is invalid. - A username must have at least 5 characters. - Sorry, a username can't start with a number. - You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.\n\nYou can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters. + Apodo + Tu apodo + Lo siento, este apodo ya está ocupado. + Lo siento, este apodo es inválido. + Un apodo debe tener al menos 5 caracteres. + El apodo no debe exceder los 32 caracteres. + Lo siento, un apodo no puede comenzar con un número. + Puedes elegir un apodo en ]]>Telegram]]>. Si lo haces, otras personas te podrán encontrar por ese apodo y contactarte sin saber tu número de teléfono.
    ]]>Puedes usar ]]>a–z]]>, ]]>0–9]]> y guiones bajos. La longitud mínima es de ]]>5]]> caracteres.
    + Verificando apodo... + %1$s está disponible. Restablecer las notificaciones Tamaño del texto @@ -265,7 +269,7 @@ Desactivadas Con pantalla encendida Con pantalla apagada - Mostrar siempre + Mostrar siempre Globo en el ícono Corto Largo @@ -290,7 +294,7 @@ Enviar ubicación Compartir ubicación - Mostrar todas las fotos y vídeos + Ir a Fotos y vídeos Guardar en galería %1$d de %2$d Galería @@ -408,12 +412,12 @@ %1$d miembros %1$d miembros %1$d miembros - y %1$d personas más escriben - y %1$d personas más escriben - y %1$d personas más escriben - y %1$d personas más escriben - y %1$d personas más escriben - y %1$d personas más escriben + y %1$d personas más están escribiendo + y %1$d persona más están escribiendo + y %1$d personas más están escribiendo + y %1$d personas más están escribiendo + y %1$d personas más están escribiendo + y %1$d personas más están escribiendo Sin mensajes nuevos %1$d nuevo mensaje %1$d nuevos mensajes @@ -432,36 +436,36 @@ de %1$d contactos de %1$d contactos de %1$d contactos - %1$d seconds - %1$d second - %1$d seconds - %1$d seconds - %1$d seconds - %1$d seconds - %1$d minutes - %1$d minute - %1$d minutes - %1$d minutes - %1$d minutes - %1$d minutes - %1$d hours - %1$d hour - %1$d hours - %1$d hours - %1$d hours - %1$d hours - %1$d days - %1$d day - %1$d days - %1$d days - %1$d days - %1$d days - %1$d weeks - %1$d week - %1$d weeks - %1$d weeks - %1$d weeks - %1$d weeks + %1$d segundos + %1$d segundo + %1$d segundos + %1$d segundos + %1$d segundos + %1$d segundos + %1$d minutos + %1$d minuto + %1$d minutos + %1$d minutos + %1$d minutos + %1$d minutos + %1$d horas + %1$d hora + %1$d horas + %1$d horas + %1$d horas + %1$d horas + %1$d días + %1$d día + %1$d días + %1$d días + %1$d días + %1$d días + %1$d semanas + %1$d semana + %1$d semanas + %1$d semanas + %1$d semanas + %1$d semanas dd \'de\' MMM dd.MM.yy diff --git a/TMessagesProj/src/main/res/values-it/strings.xml b/TMessagesProj/src/main/res/values-it/strings.xml index 46c1f712..90f500a9 100644 --- a/TMessagesProj/src/main/res/values-it/strings.xml +++ b/TMessagesProj/src/main/res/values-it/strings.xml @@ -51,6 +51,7 @@ Elimina ed esci Nome nascosto Seleziona chat + %1$s sta usando una versione vecchia di Telegram, quindi le foto segrete verranno visualizzate in modalità di compatibilità.\n\nUna volta che %2$s avrà aggiornato Telegram, le foto con il timer minore di 1 minuto funzioneranno in modalità \'Tieni premuto per vedere\' , e verrai notificato ogni volta che l\'altro esegue uno screenshot. Lista broadcast Nuova lista broadcast @@ -152,7 +153,7 @@ Seleziona contatto Ancora nessun contatto - Ciao, passa a Telegram: http://telegram.org/dl2 + Ehi, è il momento di passare a Telegram: http://telegram.org/dl2 oggi alle ieri alle in linea @@ -160,7 +161,7 @@ ultimo accesso ultimo accesso Invita amici - GLOBAL SEARCH + RICERCA GLOBALE Invia messaggio a... Immetti il nome del gruppo @@ -198,16 +199,19 @@ Timer di autodistruzione Spento Questa immagine è una visualizzazione della chiave di cifratura per questa chat segreta con ]]>%1$s]]>.
    ]]>Se questa immagine è uguale sul telefono di ]]>%2$s]]>, la chat è sicura al 200%%.
    ]]>Per saperne di più, visita Telegram.org
    - Unknown + Sconosciuto INFO Telefono - Username - Your Username - Sorry, this username is already taken. - Sorry, this username is invalid. - A username must have at least 5 characters. - Sorry, a username can't start with a number. - You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.\n\nYou can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters. + Nome utente + Il tuo Nome Utente + Nome utente già preso. + Nome utente non valido. + Il minimo per un nome utente è 5 caratteri. + Il massimo per un nome utente è 32 caratteri. + Un nome utente non può iniziare con numeri. + Puoi scegliere un nome utente su ]]>Telegram]]>. Se lo fai, le altre persone potranno trovarti tramite questo nome utente e contattarti senza conoscere il tuo numero di telefono.
    ]]>Puoi usare ]]>a–z]]>, ]]>0–9]]> e underscore. La lunghezza minima è di ]]>5]]> caratteri.
    + Controllando il nome utente... + %1$s è disponibile. Ripristina tutte le impostazioni di notifica predefinite Dimensione testo messaggi @@ -387,7 +391,7 @@ Potente Basato sul cloud Privato - L\'app di messaggi più veloce
    ]]>al mondo.]]>È gratuita
    ]]> e sicura]]>. + L\'app di messaggi più veloce]]> al mondo.]]>È gratuita]]> e sicura]]>. Telegram]]> consegna i messaggi più]]>velocemente di qualsiasi altra app. Telegram]]> sarà sempre gratuito.]]>Nessuna pubblicità. Nessun abbonamento. Telegram]]> protegge i tuoi messaggi]]>dagli attacchi degli hacker. @@ -432,36 +436,36 @@ da %1$d contatti da %1$d contatti da %1$d contatti - %1$d seconds - %1$d second - %1$d seconds - %1$d seconds - %1$d seconds - %1$d seconds - %1$d minutes - %1$d minute - %1$d minutes - %1$d minutes - %1$d minutes - %1$d minutes - %1$d hours - %1$d hour - %1$d hours - %1$d hours - %1$d hours - %1$d hours - %1$d days - %1$d day - %1$d days - %1$d days - %1$d days - %1$d days - %1$d weeks - %1$d week - %1$d weeks - %1$d weeks - %1$d weeks - %1$d weeks + %1$d secondi + %1$d secondo + %1$d secondi + %1$d secondi + %1$d secondi + %1$d secondi + %1$d minuti + %1$d minuto + %1$d minuti + %1$d minuti + %1$d minuti + %1$d minuti + %1$d ore + %1$d ora + %1$d ore + %1$d ore + %1$d ore + %1$d ore + %1$d giorni + %1$d giorno + %1$d giorni + %1$d giorni + %1$d giorni + %1$d giorni + %1$d settimane + %1$d settimana + %1$d settimane + %1$d settimane + %1$d settimane + %1$d settimane dd MMM dd.MM.yy diff --git a/TMessagesProj/src/main/res/values-ko/strings.xml b/TMessagesProj/src/main/res/values-ko/strings.xml index 9b62083e..955bc663 100644 --- a/TMessagesProj/src/main/res/values-ko/strings.xml +++ b/TMessagesProj/src/main/res/values-ko/strings.xml @@ -198,7 +198,7 @@ 자동삭제 타이머 해제 이 이미지는 ]]>%1$s]]>님과의 비밀대화에 사용 중인 암호화 키의 모습입니다.
    ]]>이 이미지가 ]]>%2$s]]>님의 암호화 키와 똑같다면 대화는 200%% 안전합니다.
    ]]>더 자세한 사항은 telegram.org 를 참고해 주세요.
    - Unknown + Unknown INFO 전화번호 Username @@ -206,8 +206,11 @@ Sorry, this username is already taken. Sorry, this username is invalid. A username must have at least 5 characters. - Sorry, a username can't start with a number. - You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.\n\nYou can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters. + A username must have maximum 32 characters. + Sorry, a username can\'t start with a number. + You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.
    ]]>You can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters.
    + Checking username... + %1$s is available. 모든 알림 설정이 초기화되었습니다 채팅 글자 크기 diff --git a/TMessagesProj/src/main/res/values-nl/strings.xml b/TMessagesProj/src/main/res/values-nl/strings.xml index dcb5fd21..489f024a 100644 --- a/TMessagesProj/src/main/res/values-nl/strings.xml +++ b/TMessagesProj/src/main/res/values-nl/strings.xml @@ -51,6 +51,7 @@ Verwijderen en verlaten Verborgen naam Kies een gesprek + %1$s gebruikt een oudere versie van Telegram, dus worden geheime foto\'s weergegeven in de compatibiliteitsmodus.\n\nZodra %2$s Telegram update werken foto\'s met timers voor 1 minuut of minder in de \'Houd ingedrukt om te bekijken\'-modus en krijg je een bericht wanneer de andere partij een schermafbeelding maakt. Verzendlijst Nieuwe verzendlijst @@ -160,7 +161,7 @@ gezien gezien Vrienden uitnodigen - GLOBAL SEARCH + WERELDWIJD ZOEKEN Bericht verzenden naar… Groepsnaam... @@ -198,16 +199,19 @@ Zelfvernietigingstimer Uit Dit is een weergave van de encryptiesleutel voor deze geheime chat met ]]>%1$s]]>.
    ]]>Als deze afbeelding er bij ]]>%2$s]]> hetzelfde uitziet, is jullie gesprek 200%% beveiligd.
    ]]>Lees meer op telegram.org.
    - Unknown - INFO + Onbekend + INFORMATIE Telefoon - Username - Your Username - Sorry, this username is already taken. - Sorry, this username is invalid. - A username must have at least 5 characters. - Sorry, a username can't start with a number. - You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.\n\nYou can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters. + Gebruikersnaam + Kies een naam + Sorry, deze gebruikersnaam is al bezet. + Sorry, deze gebruikersnaam is ongeldig. + Je naam moet minimaal 5 tekens hebben. + Je naam mag niet langer zijn dan 32 tekens. + Sorry, begincijfers zijn niet toegestaan. + Je kan een gebruikersnaam kiezen voor ]]>Telegram]]>. Hiermee kunnen anderen je vinden en contact met je opnemen zonder je telefoonnummer te weten.
    ]]>Je mag ]]>a–z]]>, ]]>0–9]]> en liggend streepje gebruiken. De minimale lengte is ]]>5]]> tekens.
    + Gebruikersnaam controleren. + %1$s is beschikbaar. Alle meldingsinstellingen herstellen Tekstgrootte berichten @@ -432,36 +436,36 @@ van %1$d contactpersonen van %1$d contactpersonen van %1$d contactpersonen - %1$d seconds - %1$d second - %1$d seconds - %1$d seconds - %1$d seconds - %1$d seconds - %1$d minutes - %1$d minute - %1$d minutes - %1$d minutes - %1$d minutes - %1$d minutes - %1$d hours - %1$d hour - %1$d hours - %1$d hours - %1$d hours - %1$d hours - %1$d days - %1$d day - %1$d days - %1$d days - %1$d days - %1$d days - %1$d weeks + %1$d seconden + %1$d seconde + %1$d seconden + %1$d seconden + %1$d seconden + %1$d seconden + %1$d minuten + %1$d minuut + %1$d minuten + %1$d minuten + %1$d minuten + %1$d minuten + %1$d uren + %1$d uur + %1$d uren + %1$d uren + %1$d uren + %1$d uren + %1$d dagen + %1$d dag + %1$d dagen + %1$d dagen + %1$d dagen + %1$d dagen + %1$d weken %1$d week - %1$d weeks - %1$d weeks - %1$d weeks - %1$d weeks + %1$d weken + %1$d weken + %1$d weken + %1$d weken dd MMM dd-MM-yy diff --git a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml index 37f19d0c..98ca4144 100644 --- a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml @@ -51,6 +51,7 @@ Apagar e sair Nome oculto Selecione uma Conversa + %1$s está usando uma versão mais antiga do Telegram, por isso fotos secretas serão mostradas em modo de compatibilidade.\n\nAssim que %2$s atualize o Telegram, fotos com timers de 1 minuto ou menos passarão a funcionar no modo ‘Toque e segure para ver’, e você será notificado caso a outra pessoa salve a tela. Lista de Broadcast Nova Lista de Broadcast @@ -114,7 +115,7 @@ Conversa secreta solicitada Conversa secreta iniciada - %1$s estabeleceu o tempo de autodestruição para %2$s + %1$s estabeleceu o tempo de autodestruição para %2$s Você estabeleceu o tempo de autodestruição para %1$s %1$s desativou o temporizador de autodestruição Você desativou o temporizador de autodestruição @@ -146,8 +147,8 @@ %1$s,\nNós detectamos um login na sua conta de um novo dispositivo %2$s\n\nDispositivo: %3$s\nLocalização: %4$s\nSe não foi você, você pode ir em Configurações - Terminar todas as sessões.\n\nAtenciosamente,\nTime do Telegram %1$s atualizou a foto do perfil Responder - Reply to %1$s - Reply to %1$s + Responder para %1$s + Responder para %1$s %1$s %2$s Selecionar Contato @@ -160,7 +161,7 @@ visto visto Convidar Amigos - GLOBAL SEARCH + BUSCA GLOBAL Enviar mensagem para... Digite o nome do grupo @@ -198,16 +199,19 @@ Tempo de autodestruição Desativado Esta imagem é uma visualização da chave criptográfica para esta conversa secreta com ]]>%1$s]]>.
    ]]>Se esta imagem aparecer da mesma forma no telefone de ]]>%2$s\'s]]>, sua conversa é 200%% segura.
    ]]>Saiba mais em telegram.org
    - Unknown + Desconhecido INFO Telefone - Username - Your Username - Sorry, this username is already taken. - Sorry, this username is invalid. - A username must have at least 5 characters. - Sorry, a username can't start with a number. - You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.\n\nYou can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters. + Nome de Usuário + Seu nome de usuário + Desculpe, este usuário já existe. + Desculpe, este usuário é inválido. + O nome de usuário deve ter pelo menos 5 caracteres. + O nome de usuário não pode exceder 32 caracteres. + Desculpe, o nome de usuário não pode começar com um número. + Você pode escolher um nome de usuário no ]]>Telegram]]>. Assim, outras pessoas poderão te encontrar pelo nome de usuário e entrar em contato sem precisar saber seu telefone.
    ]]>Você pode usar ]]>a–z]]>, ]]>0–9]]> e underline. O tamanho mínimo é ]]>5]]> caracteres.
    + Verificando nome de usuário... + %1$s está disponível. Restaurar todas as configurações de notificação Tamanho do texto nas mensagens @@ -395,7 +399,7 @@ Telegram]]> permite você acessar suas]]> mensagens de múltiplos dispositivos. Telegram]]> possui mensagens fortemente]]>encriptadas e podem se auto-destruir. Comece a conversar - + %1$d online %1$d online %1$d online @@ -432,42 +436,42 @@ de %1$d contatos de %1$d contatos de %1$d contatos - %1$d seconds - %1$d second - %1$d seconds - %1$d seconds - %1$d seconds - %1$d seconds - %1$d minutes - %1$d minute - %1$d minutes - %1$d minutes - %1$d minutes - %1$d minutes - %1$d hours - %1$d hour - %1$d hours - %1$d hours - %1$d hours - %1$d hours - %1$d days - %1$d day - %1$d days - %1$d days - %1$d days - %1$d days - %1$d weeks - %1$d week - %1$d weeks - %1$d weeks - %1$d weeks - %1$d weeks + %1$d segundos + %1$d segundo + %1$d segundos + %1$d segundos + %1$d segundos + %1$d segundos + %1$d minutos + %1$d minuto + %1$d minutos + %1$d minutos + %1$d minutos + %1$d minutos + %1$d horas + %1$d hora + %1$d horas + %1$d horas + %1$d horas + %1$d horas + %1$d dias + %1$d dia + %1$d dias + %1$d dias + %1$d dias + %1$d dias + %1$d semanas + %1$d semana + %1$d semanas + %1$d semanas + %1$d semanas + %1$d semanas dd MMM dd.MM.yy dd.MM.yyyy d MMMM - d MMMM yyyy + MMMM d, yyyy EEE HH:mm h:mm a diff --git a/TMessagesProj/src/main/res/values-pt-rPT/strings.xml b/TMessagesProj/src/main/res/values-pt-rPT/strings.xml index af0f8721..86c2b427 100644 --- a/TMessagesProj/src/main/res/values-pt-rPT/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rPT/strings.xml @@ -51,6 +51,7 @@ Apagar e sair Nome oculto Selecione uma Conversa + %1$s está usando uma versão mais antiga do Telegram, por isso fotos secretas serão mostradas em modo de compatibilidade.\n\nAssim que %2$s atualize o Telegram, fotos com timers de 1 minuto ou menos passarão a funcionar no modo ‘Toque e segure para ver’, e você será notificado caso a outra pessoa salve a tela. Lista de Broadcast Nova Lista de Broadcast @@ -114,7 +115,7 @@ Conversa secreta solicitada Conversa secreta iniciada - %1$s estabeleceu o tempo de autodestruição para %2$s + %1$s estabeleceu o tempo de autodestruição para %2$s Você estabeleceu o tempo de autodestruição para %1$s %1$s desativou o temporizador de autodestruição Você desativou o temporizador de autodestruição @@ -146,8 +147,8 @@ %1$s,\nNós detectamos um login na sua conta de um novo dispositivo %2$s\n\nDispositivo: %3$s\nLocalização: %4$s\nSe não foi você, você pode ir em Configurações - Terminar todas as sessões.\n\nAtenciosamente,\nTime do Telegram %1$s atualizou a foto do perfil Responder - Reply to %1$s - Reply to %1$s + Responder para %1$s + Responder para %1$s %1$s %2$s Selecionar Contato @@ -160,7 +161,7 @@ visto visto Convidar Amigos - GLOBAL SEARCH + BUSCA GLOBAL Enviar mensagem para... Digite o nome do grupo @@ -198,16 +199,19 @@ Tempo de autodestruição Desativado Esta imagem é uma visualização da chave criptográfica para esta conversa secreta com ]]>%1$s]]>.
    ]]>Se esta imagem aparecer da mesma forma no telefone de ]]>%2$s\'s]]>, sua conversa é 200%% segura.
    ]]>Saiba mais em telegram.org
    - Unknown + Desconhecido INFO Telefone - Username - Your Username - Sorry, this username is already taken. - Sorry, this username is invalid. - A username must have at least 5 characters. - Sorry, a username can't start with a number. - You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.\n\nYou can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters. + Nome de Usuário + Seu nome de usuário + Desculpe, este usuário já existe. + Desculpe, este usuário é inválido. + O nome de usuário deve ter pelo menos 5 caracteres. + O nome de usuário não pode exceder 32 caracteres. + Desculpe, o nome de usuário não pode começar com um número. + Você pode escolher um nome de usuário no ]]>Telegram]]>. Assim, outras pessoas poderão te encontrar pelo nome de usuário e entrar em contato sem precisar saber seu telefone.
    ]]>Você pode usar ]]>a–z]]>, ]]>0–9]]> e underline. O tamanho mínimo é ]]>5]]> caracteres.
    + Verificando nome de usuário... + %1$s está disponível. Restaurar todas as configurações de notificação Tamanho do texto nas mensagens @@ -395,7 +399,7 @@ Telegram]]> permite você acessar suas]]> mensagens de múltiplos dispositivos. Telegram]]> possui mensagens fortemente]]>encriptadas e podem se auto-destruir. Comece a conversar - + %1$d online %1$d online %1$d online @@ -432,42 +436,42 @@ de %1$d contatos de %1$d contatos de %1$d contatos - %1$d seconds - %1$d second - %1$d seconds - %1$d seconds - %1$d seconds - %1$d seconds - %1$d minutes - %1$d minute - %1$d minutes - %1$d minutes - %1$d minutes - %1$d minutes - %1$d hours - %1$d hour - %1$d hours - %1$d hours - %1$d hours - %1$d hours - %1$d days - %1$d day - %1$d days - %1$d days - %1$d days - %1$d days - %1$d weeks - %1$d week - %1$d weeks - %1$d weeks - %1$d weeks - %1$d weeks + %1$d segundos + %1$d segundo + %1$d segundos + %1$d segundos + %1$d segundos + %1$d segundos + %1$d minutos + %1$d minuto + %1$d minutos + %1$d minutos + %1$d minutos + %1$d minutos + %1$d horas + %1$d hora + %1$d horas + %1$d horas + %1$d horas + %1$d horas + %1$d dias + %1$d dia + %1$d dias + %1$d dias + %1$d dias + %1$d dias + %1$d semanas + %1$d semana + %1$d semanas + %1$d semanas + %1$d semanas + %1$d semanas dd MMM dd.MM.yy dd.MM.yyyy d MMMM - d MMMM yyyy + MMMM d, yyyy EEE HH:mm h:mm a diff --git a/TMessagesProj/src/main/res/values-v21/styles.xml b/TMessagesProj/src/main/res/values-v21/styles.xml index e9ca2a04..bf6a1918 100644 --- a/TMessagesProj/src/main/res/values-v21/styles.xml +++ b/TMessagesProj/src/main/res/values-v21/styles.xml @@ -67,7 +67,7 @@ diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index c8188486..5b0071ea 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -51,6 +51,7 @@ Delete and exit Hidden Name Select Chat + %1$s is using an older version of Telegram, so secret photos will be shown in compatibility mode.\n\nOnce %2$s updates Telegram, photos with timers for 1 minute or less will start working in \'Tap and hold to view\' mode, and you will be notified whenever the other party takes a screenshot. Broadcast List New Broadcast List @@ -198,7 +199,7 @@ Self-Destruct Timer Off This image is a visualization of the encryption key for this secret chat with ]]>%1$s]]>.
    ]]>If this image looks the same on ]]>%2$s\'s]]> phone, your chat is 200%% secure.
    ]]>Learn more at telegram.org
    - Unknown + Unknown INFO Phone Username @@ -206,8 +207,11 @@ Sorry, this username is already taken. Sorry, this username is invalid. A username must have at least 5 characters. - Sorry, a username can't start with a number. - You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.\n\nYou can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters. + The username must not exceed 32 characters. + Sorry, a username can\'t start with a number. + You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.
    ]]>You can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters.
    + Checking username... + %1$s is available. Reset all notification settings to default Messages Text Size diff --git a/TMessagesProj/src/main/res/values/styles.xml b/TMessagesProj/src/main/res/values/styles.xml index a6dcf0b9..d3f110e3 100644 --- a/TMessagesProj/src/main/res/values/styles.xml +++ b/TMessagesProj/src/main/res/values/styles.xml @@ -59,7 +59,7 @@ From ef2b368b6547526d5d3fedfa86069713bcd1c203 Mon Sep 17 00:00:00 2001 From: DrKLO Date: Wed, 22 Oct 2014 02:16:51 +0400 Subject: [PATCH 14/18] Crash fix --- TMessagesProj/build.gradle | 2 +- .../java/org/telegram/ui/Views/SettingsSectionLayout.java | 7 +++++-- TMessagesProj/src/main/res/values-de/strings.xml | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index eeca3f9b..800d5026 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -80,7 +80,7 @@ android { defaultConfig { minSdkVersion 8 targetSdkVersion 19 - versionCode 362 + versionCode 363 versionName "1.9.5" } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/SettingsSectionLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/SettingsSectionLayout.java index f7bab4ec..547e5352 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/SettingsSectionLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/SettingsSectionLayout.java @@ -14,7 +14,6 @@ import android.util.AttributeSet; import android.util.TypedValue; import android.view.Gravity; import android.view.View; -import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; @@ -26,7 +25,6 @@ public class SettingsSectionLayout extends LinearLayout { private TextView textView; private void init() { - setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); setOrientation(LinearLayout.VERTICAL); textView = new TextView(getContext()); @@ -76,6 +74,11 @@ public class SettingsSectionLayout extends LinearLayout { init(); } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED)); + } + public void setText(String text) { textView.setText(text); } diff --git a/TMessagesProj/src/main/res/values-de/strings.xml b/TMessagesProj/src/main/res/values-de/strings.xml index 796e9938..33b1f40c 100644 --- a/TMessagesProj/src/main/res/values-de/strings.xml +++ b/TMessagesProj/src/main/res/values-de/strings.xml @@ -252,7 +252,7 @@ Bedenke bitte, dass der Telegram Support von einem ehrenamtlichen Team betreut wird. Wir versuchen so schnell wie möglich zu antworten, dies kann jedoch manchmal ein bisschen dauern.
    ]]>Bitte schau auch in den Fragen und Antworten ]]> nach. Dort findest du Antworten auf die meisten Fragen und wichtige Tipps zur Problembehandlung]]>.
    Frage einen Freiwilligen Fragen und Antworten - https://telegram.org/faq/ko + https://telegram.org/faq/de Lokalisierung löschen? Falsche Sprachdatei Aktiviert From e3d2b9cece6c8bcb5069cefdd7a835a1123dcc4f Mon Sep 17 00:00:00 2001 From: DrKLO Date: Wed, 22 Oct 2014 14:11:47 +0400 Subject: [PATCH 15/18] Bug fixes --- .../telegram/android/MessagesController.java | 2 +- .../java/org/telegram/ui/ChatActivity.java | 17 +++++- .../java/org/telegram/ui/PhotoViewer.java | 17 +++++- .../org/telegram/ui/SettingsActivity.java | 2 +- .../ui/SettingsChangeUsernameActivity.java | 4 +- .../org/telegram/ui/Views/NumberPicker.java | 59 ++++++++++--------- .../src/main/res/values-ar/strings.xml | 3 +- .../src/main/res/values-de/strings.xml | 3 +- .../src/main/res/values-es/strings.xml | 3 +- .../src/main/res/values-it/strings.xml | 3 +- .../src/main/res/values-ko/strings.xml | 3 +- .../src/main/res/values-nl/strings.xml | 3 +- .../src/main/res/values-pt-rBR/strings.xml | 3 +- .../src/main/res/values-pt-rPT/strings.xml | 3 +- TMessagesProj/src/main/res/values/strings.xml | 6 +- 15 files changed, 89 insertions(+), 42 deletions(-) diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java index ea725695..20503434 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java @@ -4147,7 +4147,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(LocaleController.formatString("CreateEncryptedChatOutdatedError", R.string.CreateEncryptedChatOutdatedError, user.first_name, user.first_name)); + builder.setMessage(LocaleController.getString("CreateEncryptedChatError", R.string.CreateEncryptedChatError)); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); builder.show().setCanceledOnTouchOutside(true); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index a22bb862..7d507479 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -849,6 +849,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } startX = x; startY = y; + chatListView.setOnItemClickListener(null); openSecretPhotoRunnable = new Runnable() { @Override public void run() { @@ -857,7 +858,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } chatListView.requestDisallowInterceptTouchEvent(true); chatListView.setOnItemLongClickListener(null); - chatListView.setOnItemClickListener(null); chatListView.setLongClickable(false); openSecretPhotoRunnable = null; if (sendSecretMessageRead(messageObject)) { @@ -882,18 +882,31 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_POINTER_UP) { if (openSecretPhotoRunnable != null) { AndroidUtilities.CancelRunOnUIThread(openSecretPhotoRunnable); + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + chatListView.setOnItemClickListener(onItemClickListener); + } + }, 150); openSecretPhotoRunnable = null; + try { + Toast.makeText(v.getContext(), LocaleController.getString("PhotoTip", R.string.PhotoTip), Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } } else { if (SecretPhotoViewer.getInstance().isVisible()) { AndroidUtilities.RunOnUIThread(new Runnable() { @Override public void run() { - chatListView.setOnItemLongClickListener(onItemLongClickListener); chatListView.setOnItemClickListener(onItemClickListener); + chatListView.setOnItemLongClickListener(onItemLongClickListener); chatListView.setLongClickable(true); } }); SecretPhotoViewer.getInstance().closePhoto(); + } else { + chatListView.setOnItemClickListener(onItemClickListener); } } } else if (event.getAction() != MotionEvent.ACTION_DOWN) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index a1178e16..3e70e6b9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -101,6 +101,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private View pickerView; private TextView doneButtonTextView; private TextView doneButtonBadgeTextView; + private ImageView shareButton; private boolean canShowBottom = true; private boolean overlayViewVisible = true; @@ -595,7 +596,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat bottomLayout.setLayoutParams(layoutParams); bottomLayout.setBackgroundColor(0x7F000000); - ImageView shareButton = new ImageView(containerView.getContext()); + shareButton = new ImageView(containerView.getContext()); shareButton.setImageResource(R.drawable.ic_ab_share_white); shareButton.setScaleType(ImageView.ScaleType.CENTER); shareButton.setBackgroundResource(R.drawable.bar_selector_white); @@ -1159,6 +1160,12 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } else { menuItem.hideSubItem(gallery_menu_showall); } + if ((int) currentDialogId == 0) { + menuItem.hideSubItem(gallery_menu_save); + shareButton.setVisibility(View.GONE); + } else { + shareButton.setVisibility(View.VISIBLE); + } setImageIndex(0, true); } else if (fileLocation != null) { avatarsUserId = object.user_id; @@ -1166,6 +1173,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat imagesArrLocationsSizes.add(object.size); avatarsArr.add(new TLRPC.TL_photoEmpty()); bottomLayout.setVisibility(View.GONE); + shareButton.setVisibility(View.VISIBLE); menuItem.hideSubItem(gallery_menu_showall); setImageIndex(0, true); currentUserAvatarLocation = fileLocation; @@ -1194,6 +1202,12 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } } + if ((int) currentDialogId == 0) { + menuItem.hideSubItem(gallery_menu_save); + shareButton.setVisibility(View.GONE); + } else { + shareButton.setVisibility(View.VISIBLE); + } opennedFromMedia = true; setImageIndex(index, true); } else if (photos != null) { @@ -1203,6 +1217,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat setImageIndex(index, true); pickerView.setVisibility(View.VISIBLE); bottomLayout.setVisibility(View.GONE); + shareButton.setVisibility(View.VISIBLE); canShowBottom = false; updateSelectedCount(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java index fdcc3dd5..1c10cb54 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java @@ -1001,7 +1001,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter if (user != null && user.username != null && user.username.length() != 0) { detailTextView.setText("@" + user.username); } else { - detailTextView.setText("-"); + detailTextView.setText(LocaleController.getString("UsernameEmpty", R.string.UsernameEmpty)); } divider.setVisibility(View.INVISIBLE); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java index bf01f63f..f6cb32d1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java @@ -202,8 +202,10 @@ public class SettingsChangeUsernameActivity extends BaseFragment { builder.setMessage(LocaleController.getString("UsernameInvalid", R.string.UsernameInvalid)); } else if (error.equals("USERNAME_OCCUPIED")) { builder.setMessage(LocaleController.getString("UsernameInUse", R.string.UsernameInUse)); + } else if (error.equals("USERNAMES_UNAVAILABLE")) { + builder.setMessage(LocaleController.getString("FeatureUnavailable", R.string.FeatureUnavailable)); } else { - builder.setMessage(error); + builder.setMessage(LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred)); } builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); showAlertDialog(builder); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/NumberPicker.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/NumberPicker.java index 6dbffc09..e91a7113 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/NumberPicker.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/NumberPicker.java @@ -57,14 +57,14 @@ public class NumberPicker extends LinearLayout { private static final int DEFAULT_LAYOUT_RESOURCE_ID = 0; private static final int SIZE_UNSPECIFIED = -1; - private final TextView mInputText; - private final int mSelectionDividersDistance; - private final int mMinHeight; - private final int mMaxHeight; - private final int mMinWidth; + private TextView mInputText; + private int mSelectionDividersDistance; + private int mMinHeight; + private int mMaxHeight; + private int mMinWidth; private int mMaxWidth; - private final boolean mComputeMaxWidth; - private final int mTextSize; + private boolean mComputeMaxWidth; + private int mTextSize; private int mSelectorTextGapHeight; private String[] mDisplayedValues; private int mMinValue; @@ -76,13 +76,13 @@ public class NumberPicker extends LinearLayout { private long mLongPressUpdateInterval = DEFAULT_LONG_PRESS_UPDATE_INTERVAL; private final SparseArray mSelectorIndexToStringCache = new SparseArray(); private final int[] mSelectorIndices = new int[SELECTOR_WHEEL_ITEM_COUNT]; - private final Paint mSelectorWheelPaint; - private final Drawable mVirtualButtonPressedDrawable; + private Paint mSelectorWheelPaint; + private Drawable mVirtualButtonPressedDrawable; private int mSelectorElementHeight; private int mInitialScrollOffset = Integer.MIN_VALUE; private int mCurrentScrollOffset; - private final Scroller mFlingScroller; - private final Scroller mAdjustScroller; + private Scroller mFlingScroller; + private Scroller mAdjustScroller; private int mPreviousScrollerY; private ChangeCurrentByOneFromLongPressCommand mChangeCurrentByOneFromLongPressCommand; private float mLastDownEventY; @@ -93,9 +93,9 @@ public class NumberPicker extends LinearLayout { private int mMinimumFlingVelocity; private int mMaximumFlingVelocity; private boolean mWrapSelectorWheel; - private final int mSolidColor; - private final Drawable mSelectionDivider; - private final int mSelectionDividerHeight; + private int mSolidColor; + private Drawable mSelectionDivider; + private int mSelectionDividerHeight; private int mScrollState = OnScrollListener.SCROLL_STATE_IDLE; private boolean mIngonreMoveEvents; private int mTopSelectionDividerTop; @@ -103,7 +103,7 @@ public class NumberPicker extends LinearLayout { private int mLastHoveredChildVirtualViewId; private boolean mIncrementVirtualButtonPressed; private boolean mDecrementVirtualButtonPressed; - private final PressedStateHelper mPressedStateHelper; + private PressedStateHelper mPressedStateHelper; private int mLastHandledDownDpadKeyCode = -1; public interface OnValueChangeListener { @@ -122,17 +122,7 @@ public class NumberPicker extends LinearLayout { public String format(int value); } - public NumberPicker(Context context) { - this(context, null); - } - - public NumberPicker(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public NumberPicker(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - + private void init() { mSolidColor = 0; mSelectionDivider = getResources().getDrawable(R.drawable.numberpicker_selection_divider); @@ -169,7 +159,7 @@ public class NumberPicker extends LinearLayout { mInputText.setBackgroundResource(0); mInputText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18); - ViewConfiguration configuration = ViewConfiguration.get(context); + ViewConfiguration configuration = ViewConfiguration.get(getContext()); mTouchSlop = configuration.getScaledTouchSlop(); mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity(); mMaximumFlingVelocity = configuration.getScaledMaximumFlingVelocity() / SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT; @@ -191,6 +181,21 @@ public class NumberPicker extends LinearLayout { updateInputTextView(); } + public NumberPicker(Context context) { + super(context); + init(); + } + + public NumberPicker(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public NumberPicker(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { final int msrdWdth = getMeasuredWidth(); diff --git a/TMessagesProj/src/main/res/values-ar/strings.xml b/TMessagesProj/src/main/res/values-ar/strings.xml index 8bbcb33a..9e24a7e9 100644 --- a/TMessagesProj/src/main/res/values-ar/strings.xml +++ b/TMessagesProj/src/main/res/values-ar/strings.xml @@ -193,7 +193,6 @@ الهاتف إبدأ محادثة سرية حدث خطأ. - لا يمكن إنشاء محادثة سرية مع %1$s.\n\n%2$s يستخدم إصدار قديم من تيليجرام ولا بد أن يقوم بالتحديث أولًا. محادثة سرية مفتاح التشفير عداد التدمير الذاتي @@ -212,6 +211,8 @@ يمكنك اختيار اسم مستخدم في ]]>تيليجرام]]>. إذا قمت بذلك، سيستطيع الناس إيجادك باستخدام الاسم المستخدم والتواصل معك من دون معرفة رقمك.
    ]]>يمكنك استخدام ]]>حروف اللغة الإنجليزية]]>, ]]>وأرقامها]]> و كذلك الخط. لا بد من استخدام ]]>٥]]> حروف على الأقل.
    جاري مراجعة اسم المستخدم... %1$s متاح. + None + An error occurred تم تعيين كافة الإشعارات افتراضيا حجم نص الرسائل diff --git a/TMessagesProj/src/main/res/values-de/strings.xml b/TMessagesProj/src/main/res/values-de/strings.xml index 33b1f40c..3fe8b822 100644 --- a/TMessagesProj/src/main/res/values-de/strings.xml +++ b/TMessagesProj/src/main/res/values-de/strings.xml @@ -193,7 +193,6 @@ TELEFON Geheimen Chat starten Es ist ein Fehler aufgetreten. - Geheimer Chat konnte mit %1$s nicht gestartet werden.\n\n%2$s benutzt eine ältere Version von Telegram und muss diese erst aktualisieren. Geheimer Chat Geheimer Schlüssel Selbstzerstörungs-Timer @@ -212,6 +211,8 @@ Wähle einen Benutzernamen, wenn du von anderen bei]]>Telegram]]>gefunden werden willst – ohne, dass sie deine Nummer kennen müssen.
    ]]>Erlaubt sind ]]>a–z]]>, ]]>0–9]]> und Unterstriche. Die Mindestlänge beträgt ]]>5]]> Zeichen.
    Prüfe Benutzername... %1$s ist verfügbar. + None + An error occurred Alle Einstellungen für Mitteilungen zurücksetzen Textgröße für Nachrichten diff --git a/TMessagesProj/src/main/res/values-es/strings.xml b/TMessagesProj/src/main/res/values-es/strings.xml index 87f41149..2eecba92 100644 --- a/TMessagesProj/src/main/res/values-es/strings.xml +++ b/TMessagesProj/src/main/res/values-es/strings.xml @@ -193,7 +193,6 @@ TELÉFONO Iniciar chat secreto Ocurrió un error. - No podemos crear un chat secreto con %1$s.\n\n%2$s está usando una versión antigua de Telegram y debe actualizarla. Chat secreto Clave de cifrado Autodestrucción @@ -212,6 +211,8 @@ Puedes elegir un apodo en ]]>Telegram]]>. Si lo haces, otras personas te podrán encontrar por ese apodo y contactarte sin saber tu número de teléfono.
    ]]>Puedes usar ]]>a–z]]>, ]]>0–9]]> y guiones bajos. La longitud mínima es de ]]>5]]> caracteres.
    Verificando apodo... %1$s está disponible. + None + An error occurred Restablecer las notificaciones Tamaño del texto diff --git a/TMessagesProj/src/main/res/values-it/strings.xml b/TMessagesProj/src/main/res/values-it/strings.xml index 90f500a9..0b37c268 100644 --- a/TMessagesProj/src/main/res/values-it/strings.xml +++ b/TMessagesProj/src/main/res/values-it/strings.xml @@ -193,7 +193,6 @@ TELEFONO Inizia chat segreta Si è verificato un errore. - Impossibile creare una chat segreta con %1$s.\n\n%2$s sta usando una vecchia versione di Telegram e deve prima aggiornarla. Chat segreta Chiave di cifratura Timer di autodistruzione @@ -212,6 +211,8 @@ Puoi scegliere un nome utente su ]]>Telegram]]>. Se lo fai, le altre persone potranno trovarti tramite questo nome utente e contattarti senza conoscere il tuo numero di telefono.
    ]]>Puoi usare ]]>a–z]]>, ]]>0–9]]> e underscore. La lunghezza minima è di ]]>5]]> caratteri.
    Controllando il nome utente... %1$s è disponibile. + None + An error occurred Ripristina tutte le impostazioni di notifica predefinite Dimensione testo messaggi diff --git a/TMessagesProj/src/main/res/values-ko/strings.xml b/TMessagesProj/src/main/res/values-ko/strings.xml index 955bc663..3aa93ccc 100644 --- a/TMessagesProj/src/main/res/values-ko/strings.xml +++ b/TMessagesProj/src/main/res/values-ko/strings.xml @@ -192,7 +192,6 @@ 전화번호 비밀대화 시작 오류가 발생했습니다. - %1$s님의 텔레그램 버전이 낮아 비밀대화를 시작할 수 없습니다.\n\n비밀대화를 시작하려면 %2$s님이 텔레그램을 업데이트해야 합니다. 비밀대화 암호화 키 자동삭제 타이머 @@ -211,6 +210,8 @@ You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.
    ]]>You can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters.
    Checking username... %1$s is available. + None + An error occurred 모든 알림 설정이 초기화되었습니다 채팅 글자 크기 diff --git a/TMessagesProj/src/main/res/values-nl/strings.xml b/TMessagesProj/src/main/res/values-nl/strings.xml index 489f024a..7916a2fb 100644 --- a/TMessagesProj/src/main/res/values-nl/strings.xml +++ b/TMessagesProj/src/main/res/values-nl/strings.xml @@ -193,7 +193,6 @@ TELEFOON Geheime chat starten Er is een fout opgetreden. - Kan geen geheime chat starten met %1$s.\n\n%2$s gebruikt een oudere versie van Telegram en moet eerst een update installeren. Geheime chat Encryptiesleutel Zelfvernietigingstimer @@ -212,6 +211,8 @@ Je kan een gebruikersnaam kiezen voor ]]>Telegram]]>. Hiermee kunnen anderen je vinden en contact met je opnemen zonder je telefoonnummer te weten.
    ]]>Je mag ]]>a–z]]>, ]]>0–9]]> en liggend streepje gebruiken. De minimale lengte is ]]>5]]> tekens.
    Gebruikersnaam controleren. %1$s is beschikbaar. + None + An error occurred Alle meldingsinstellingen herstellen Tekstgrootte berichten diff --git a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml index 98ca4144..a6270eed 100644 --- a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml @@ -193,7 +193,6 @@ TELEFONE Iniciar Conversa Secreta Ocorreu um erro. - Não é possível criar uma conversa secreta com %1$s.\n\n%2$s está usando uma versão antiga do Telegram e precisa ser atualizada. Conversa Secreta Chave criptográfica Tempo de autodestruição @@ -212,6 +211,8 @@ Você pode escolher um nome de usuário no ]]>Telegram]]>. Assim, outras pessoas poderão te encontrar pelo nome de usuário e entrar em contato sem precisar saber seu telefone.
    ]]>Você pode usar ]]>a–z]]>, ]]>0–9]]> e underline. O tamanho mínimo é ]]>5]]> caracteres.
    Verificando nome de usuário... %1$s está disponível. + None + An error occurred Restaurar todas as configurações de notificação Tamanho do texto nas mensagens diff --git a/TMessagesProj/src/main/res/values-pt-rPT/strings.xml b/TMessagesProj/src/main/res/values-pt-rPT/strings.xml index 86c2b427..b11dad27 100644 --- a/TMessagesProj/src/main/res/values-pt-rPT/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rPT/strings.xml @@ -193,7 +193,6 @@ TELEFONE Iniciar Conversa Secreta Ocorreu um erro. - Não é possível criar uma conversa secreta com %1$s.\n\n%2$s está usando uma versão antiga do Telegram e precisa ser atualizada. Conversa Secreta Chave criptográfica Tempo de autodestruição @@ -212,6 +211,8 @@ Você pode escolher um nome de usuário no ]]>Telegram]]>. Assim, outras pessoas poderão te encontrar pelo nome de usuário e entrar em contato sem precisar saber seu telefone.
    ]]>Você pode usar ]]>a–z]]>, ]]>0–9]]> e underline. O tamanho mínimo é ]]>5]]> caracteres.
    Verificando nome de usuário... %1$s está disponível. + None + An error occurred Restaurar todas as configurações de notificação Tamanho do texto nas mensagens diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index 5b0071ea..afb85da5 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -51,6 +51,7 @@ Delete and exit Hidden Name Select Chat + Tap and hold to view %1$s is using an older version of Telegram, so secret photos will be shown in compatibility mode.\n\nOnce %2$s updates Telegram, photos with timers for 1 minute or less will start working in \'Tap and hold to view\' mode, and you will be notified whenever the other party takes a screenshot. Broadcast List @@ -193,7 +194,6 @@ PHONE Start Secret Chat An error occurred. - Cannot create a secret chat with %1$s.\n\n%2$s is using an older version of Telegram and needs to update first. Secret Chat Encryption Key Self-Destruct Timer @@ -202,6 +202,7 @@ Unknown INFO Phone + Username Your Username Sorry, this username is already taken. @@ -212,6 +213,8 @@ You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.
    ]]>You can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters.
    Checking username... %1$s is available. + None + An error occurred. Reset all notification settings to default Messages Text Size @@ -383,6 +386,7 @@ forward from my name Send messages to %1$s? Forward messages to %1$s? + Sorry, this feature is currently not available in your country. Telegram Fast From e5def002f7e81d6cb55357f82eef097b90dc3b01 Mon Sep 17 00:00:00 2001 From: DrKLO Date: Thu, 23 Oct 2014 00:01:07 +0400 Subject: [PATCH 16/18] Different improvements --- TMessagesProj/build.gradle | 2 +- .../telegram/android/AndroidUtilities.java | 6 +- .../org/telegram/android/MediaController.java | 6 +- .../org/telegram/android/MessageObject.java | 33 +- .../telegram/android/MessagesController.java | 71 ++- .../org/telegram/android/MessagesStorage.java | 109 +++- .../telegram/android/SendMessagesHelper.java | 459 ++++++++++------ .../org/telegram/messenger/FileLoader.java | 22 + .../org/telegram/messenger/TLClassStore.java | 2 +- .../java/org/telegram/messenger/TLRPC.java | 29 +- .../telegram/ui/Cells/ChatMessageCell.java | 47 +- .../java/org/telegram/ui/ChatActivity.java | 74 ++- .../java/org/telegram/ui/PhotoViewer.java | 11 +- .../ui/SettingsChangeUsernameActivity.java | 4 +- .../org/telegram/ui/VideoEditorActivity.java | 6 + .../org/telegram/ui/Views/NumberPicker.java | 23 +- .../java/org/telegram/ui/Views/Scroller.java | 502 ++++++++++++++++++ .../src/main/res/values-ar/strings.xml | 7 +- .../src/main/res/values-de/strings.xml | 9 +- .../src/main/res/values-es/strings.xml | 17 +- .../src/main/res/values-it/strings.xml | 7 +- .../src/main/res/values-ko/strings.xml | 96 ++-- .../src/main/res/values-nl/strings.xml | 9 +- .../src/main/res/values-pt-rBR/strings.xml | 7 +- .../src/main/res/values-pt-rPT/strings.xml | 7 +- 25 files changed, 1222 insertions(+), 343 deletions(-) create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Views/Scroller.java diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index 800d5026..d0dbed6a 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -80,7 +80,7 @@ android { defaultConfig { minSdkVersion 8 targetSdkVersion 19 - versionCode 363 + versionCode 371 versionName "1.9.5" } } diff --git a/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java index b4f28c26..ed9a09e9 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java @@ -425,7 +425,7 @@ public class AndroidUtilities { final NumberPicker numberPicker = new NumberPicker(context); numberPicker.setMinValue(0); numberPicker.setMaxValue(20); - if (encryptedChat.ttl >= 0 && encryptedChat.ttl < 16) { + if (encryptedChat.ttl > 0 && encryptedChat.ttl < 16) { numberPicker.setValue(encryptedChat.ttl); } else if (encryptedChat.ttl == 30) { numberPicker.setValue(16); @@ -437,6 +437,8 @@ public class AndroidUtilities { numberPicker.setValue(19); } else if (encryptedChat.ttl == 60 * 60 * 24 * 7) { numberPicker.setValue(20); + } else if (encryptedChat.ttl == 0) { + numberPicker.setValue(5); } numberPicker.setFormatter(new NumberPicker.Formatter() { @Override @@ -479,7 +481,7 @@ public class AndroidUtilities { encryptedChat.ttl = 60 * 60 * 24 * 7; } if (oldValue != encryptedChat.ttl) { - SendMessagesHelper.getInstance().sendTTLMessage(encryptedChat); + SendMessagesHelper.getInstance().sendTTLMessage(encryptedChat, null); MessagesStorage.getInstance().updateEncryptedChatTTL(encryptedChat); } } diff --git a/TMessagesProj/src/main/java/org/telegram/android/MediaController.java b/TMessagesProj/src/main/java/org/telegram/android/MediaController.java index 1464050f..ad08add7 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MediaController.java @@ -791,7 +791,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel photoW = bmOptions.outWidth; photoH = bmOptions.outHeight; } - if (photoW == 0 || photoH == 0 || (photoW == width && photoH == height || photoH == width && photoW == height)) { + if (photoW <= 0 || photoH <= 0 || (photoW == width && photoH == height || photoH == width && photoW == height)) { screenshotDates.add(date); } } catch (Exception e) { @@ -834,7 +834,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } } if (send) { - SendMessagesHelper.getInstance().sendScreenshotMessage(lastSecretChat, lastSecretChatVisibleMessages); + SendMessagesHelper.getInstance().sendScreenshotMessage(lastSecretChat, lastSecretChatVisibleMessages, null); } } @@ -2200,6 +2200,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel File inputFile = new File(videoPath); if (!inputFile.canRead()) { + didWriteData(messageObject, cacheFile, true, true); return false; } @@ -2577,6 +2578,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel FileLog.e("tmessages", "time = " + (System.currentTimeMillis() - time)); } } else { + didWriteData(messageObject, cacheFile, true, true); return false; } didWriteData(messageObject, cacheFile, true, error); diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java index dea61ff8..953bdb11 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessageObject.java @@ -232,7 +232,7 @@ public class MessageObject { } else { messageText = LocaleController.formatString("NotificationContactNewPhoto", R.string.NotificationContactNewPhoto, ""); } - } else if (message.action instanceof TLRPC.TL_messageEcryptedAction) { + } else if (message.action instanceof TLRPC.TL_messageEncryptedAction) { if (message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages) { if (isFromMe()) { messageText = LocaleController.formatString("ActionTakeScreenshootYou", R.string.ActionTakeScreenshootYou); @@ -243,6 +243,29 @@ public class MessageObject { messageText = LocaleController.formatString("ActionTakeScreenshoot", R.string.ActionTakeScreenshoot).replace("un1", ""); } } + } else if (message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { + TLRPC.TL_decryptedMessageActionSetMessageTTL action = (TLRPC.TL_decryptedMessageActionSetMessageTTL) message.action.encryptedAction; + if (action.ttl_seconds != 0) { + if (isFromMe()) { + messageText = LocaleController.formatString("MessageLifetimeChangedOutgoing", R.string.MessageLifetimeChangedOutgoing, AndroidUtilities.formatTTLString(action.ttl_seconds)); + } else { + if (fromUser != null) { + messageText = LocaleController.formatString("MessageLifetimeChanged", R.string.MessageLifetimeChanged, fromUser.first_name, AndroidUtilities.formatTTLString(action.ttl_seconds)); + } else { + messageText = LocaleController.formatString("MessageLifetimeChanged", R.string.MessageLifetimeChanged, "", AndroidUtilities.formatTTLString(action.ttl_seconds)); + } + } + } else { + if (isFromMe()) { + messageText = LocaleController.getString("MessageLifetimeYouRemoved", R.string.MessageLifetimeYouRemoved); + } else { + if (fromUser != null) { + messageText = LocaleController.formatString("MessageLifetimeRemoved", R.string.MessageLifetimeRemoved, fromUser.first_name); + } else { + messageText = LocaleController.formatString("MessageLifetimeRemoved", R.string.MessageLifetimeRemoved, ""); + } + } + } } } else if (message.action instanceof TLRPC.TL_messageActionCreatedBroadcastList) { messageText = LocaleController.formatString("YouCreatedBroadcastList", R.string.YouCreatedBroadcastList); @@ -301,6 +324,14 @@ public class MessageObject { } else if (message.action instanceof TLRPC.TL_messageActionChatEditPhoto || message.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) { contentType = 4; type = 11; + } else if (message.action instanceof TLRPC.TL_messageEncryptedAction) { + if (message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages || message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { + contentType = 4; + type = 10; + } else { + contentType = -1; + type = -1; + } } else { contentType = 4; type = 10; diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java index 20503434..eb95c9a5 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java @@ -980,7 +980,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesDeleted, messages); if (randoms != null && encryptedChat != null && !randoms.isEmpty()) { - SendMessagesHelper.getInstance().sendMessagesDeleteMessage(randoms, encryptedChat); + SendMessagesHelper.getInstance().sendMessagesDeleteMessage(encryptedChat, randoms, null); } ArrayList toSend = new ArrayList(); @@ -1071,7 +1071,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter }); } else { if (onlyHistory) { - SendMessagesHelper.getInstance().sendClearHistoryMessage(getEncryptedChat(high_id)); + SendMessagesHelper.getInstance().sendClearHistoryMessage(getEncryptedChat(high_id), null); } else { declineSecretChat(high_id); } @@ -1643,6 +1643,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter putChats(dialogsRes.chats, isCache); if (encChats != null) { for (TLRPC.EncryptedChat encryptedChat : encChats) { + if (encryptedChat instanceof TLRPC.TL_encryptedChat && AndroidUtilities.getMyLayerVersion(encryptedChat.layer) < SendMessagesHelper.CURRENT_SECRET_CHAT_LAYER) { + SendMessagesHelper.getInstance().sendNotifyLayerMessage(encryptedChat, null); + } putEncryptedChat(encryptedChat, true); } } @@ -1707,7 +1710,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter }); } - public void markMessageAsRead(final long dialog_id, final long random_id) { + public void markMessageAsRead(final long dialog_id, final long random_id, int ttl) { if (random_id == 0 || dialog_id == 0) { return; } @@ -1722,12 +1725,11 @@ public class MessagesController implements NotificationCenter.NotificationCenter } ArrayList random_ids = new ArrayList(); random_ids.add(random_id); - SendMessagesHelper.getInstance().sendMessagesReadMessage(random_ids, chat); - if (chat.ttl > 0) { + SendMessagesHelper.getInstance().sendMessagesReadMessage(chat, random_ids, null); + if (ttl > 0) { int time = ConnectionsManager.getInstance().getCurrentTime(); MessagesStorage.getInstance().createTaskForSecretChat(chat.id, time, time, 0, random_ids); } - //TODO resend request } public void markDialogAsRead(final long dialog_id, final int max_id, final int max_positive_id, final int offset, final int max_date, final boolean was, final boolean popup) { @@ -3558,7 +3560,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter public TLRPC.Message decryptMessage(TLRPC.EncryptedMessage message) { final TLRPC.EncryptedChat chat = getEncryptedChatDB(message.chat_id); - if (chat == null) { + if (chat == null || chat instanceof TLRPC.TL_encryptedChatDiscarded) { return null; } ByteBufferDesc is = BuffersStorage.getInstance().getFreeBuffer(message.bytes.length); @@ -3582,13 +3584,38 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (object instanceof TLRPC.TL_decryptedMessageLayer) { final TLRPC.TL_decryptedMessageLayer layer = (TLRPC.TL_decryptedMessageLayer)object; - AndroidUtilities.RunOnUIThread(new Runnable() { - @Override - public void run() { - chat.seq_in = layer.out_seq_no; - MessagesStorage.getInstance().updateEncryptedChatSeq(chat); + if (chat.seq_in == 0 && chat.seq_out == 0) { + if (chat.admin_id == UserConfig.getClientUserId()) { + chat.seq_out = 1; + } else { + chat.seq_in = 1; } - }); + } + if (chat.seq_in != layer.out_seq_no && chat.seq_in != layer.out_seq_no - 2) { + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + final TLRPC.TL_encryptedChatDiscarded newChat = new TLRPC.TL_encryptedChatDiscarded(); + newChat.id = chat.id; + newChat.user_id = chat.user_id; + newChat.auth_key = chat.auth_key; + newChat.seq_in = chat.seq_in; + newChat.seq_out = chat.seq_out; + MessagesStorage.getInstance().updateEncryptedChat(newChat); + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + putEncryptedChat(newChat, false); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, newChat); + } + }); + declineSecretChat(chat.id); + } + }); + return null; + } + chat.seq_in = layer.out_seq_no; + MessagesStorage.getInstance().updateEncryptedChatSeq(chat); object = layer.message; } @@ -3597,8 +3624,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter TLRPC.TL_message newMessage = null; if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 17) { newMessage = new TLRPC.TL_message_secret(); + newMessage.ttl = decryptedMessage.ttl; } else { newMessage = new TLRPC.TL_message(); + newMessage.ttl = chat.ttl; } newMessage.message = decryptedMessage.message; newMessage.date = message.date; @@ -3610,7 +3639,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter newMessage.to_id.user_id = UserConfig.getClientUserId(); newMessage.flags = TLRPC.MESSAGE_FLAG_UNREAD; newMessage.dialog_id = ((long)chat.id) << 32; - newMessage.ttl = chat.ttl; if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaEmpty) { newMessage.media = new TLRPC.TL_messageMediaEmpty(); } else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaContact) { @@ -3751,13 +3779,15 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL || serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages) { TLRPC.TL_messageService newMessage = new TLRPC.TL_messageService(); if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { - newMessage.action = new TLRPC.TL_messageActionTTLChange(); + newMessage.action = new TLRPC.TL_messageEncryptedAction(); if (serviceMessage.action.ttl_seconds < 0 || serviceMessage.action.ttl_seconds > 60 * 60 * 24 * 365) { serviceMessage.action.ttl_seconds = 60 * 60 * 24 * 365; } - newMessage.action.ttl = chat.ttl = serviceMessage.action.ttl_seconds; + chat.ttl = serviceMessage.action.ttl_seconds; + newMessage.action.encryptedAction = serviceMessage.action; + MessagesStorage.getInstance().updateEncryptedChatTTL(chat); } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages) { - newMessage.action = new TLRPC.TL_messageEcryptedAction(); + newMessage.action = new TLRPC.TL_messageEncryptedAction(); newMessage.action.encryptedAction = serviceMessage.action; } newMessage.local_id = newMessage.id = UserConfig.getNewMessageId(); @@ -3768,7 +3798,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter newMessage.to_id = new TLRPC.TL_peerUser(); newMessage.to_id.user_id = UserConfig.getClientUserId(); newMessage.dialog_id = ((long)chat.id) << 32; - MessagesStorage.getInstance().updateEncryptedChatTTL(chat); return newMessage; } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionFlushHistory) { final long did = ((long)chat.id) << 32; @@ -3818,7 +3847,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter chat.layer = AndroidUtilities.setPeerLayerVersion(chat.layer, serviceMessage.action.layer); MessagesStorage.getInstance().updateEncryptedChatLayer(chat); if (currentPeerLayer < 17) { - SendMessagesHelper.getInstance().sendNotifyLayerMessage(chat); + SendMessagesHelper.getInstance().sendNotifyLayerMessage(chat, null); } } }); @@ -3878,7 +3907,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter public void run() { putEncryptedChat(encryptedChat, false); NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, encryptedChat); - SendMessagesHelper.getInstance().sendNotifyLayerMessage(encryptedChat); + SendMessagesHelper.getInstance().sendNotifyLayerMessage(encryptedChat, null); } }); } else { @@ -4003,7 +4032,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter public void run() { putEncryptedChat(newChat, false); NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, newChat); - SendMessagesHelper.getInstance().sendNotifyLayerMessage(newChat); + SendMessagesHelper.getInstance().sendNotifyLayerMessage(newChat, null); } }); } diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java index 31e58ea8..479401bf 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java @@ -110,6 +110,7 @@ public class MessagesStorage { database.executeFast("CREATE TABLE download_queue(uid INTEGER, type INTEGER, date INTEGER, data BLOB, PRIMARY KEY (uid, type));").stepThis().dispose(); database.executeFast("CREATE TABLE dialog_settings(did INTEGER PRIMARY KEY, flags INTEGER);").stepThis().dispose(); database.executeFast("CREATE TABLE messages_seq(mid INTEGER PRIMARY KEY, seq_in INTEGER, seq_out INTEGER);").stepThis().dispose(); + //database.executeFast("CREATE TABLE attach_data(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose(); database.executeFast("CREATE TABLE user_contacts_v6(uid INTEGER PRIMARY KEY, fname TEXT, sname TEXT)").stepThis().dispose(); @@ -137,6 +138,9 @@ public class MessagesStorage { database.executeFast("CREATE INDEX IF NOT EXISTS mid_out_idx_messages ON messages(mid, out);").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS task_idx_messages ON messages(uid, out, read_state, ttl, date, send_state);").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS send_state_idx_messages ON messages(mid, send_state, date) WHERE mid < 0 AND send_state = 1;").stepThis().dispose(); + + database.executeFast("CREATE INDEX IF NOT EXISTS seq_idx_messages_seq ON messages_seq(seq_in, seq_out);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 7").stepThis().dispose(); } else { try { @@ -292,6 +296,7 @@ public class MessagesStorage { } if (version == 6 && version < 7) { database.executeFast("CREATE TABLE IF NOT EXISTS messages_seq(mid INTEGER PRIMARY KEY, seq_in INTEGER, seq_out INTEGER);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS seq_idx_messages_seq ON messages_seq(seq_in, seq_out);").stepThis().dispose(); database.executeFast("ALTER TABLE enc_chats ADD COLUMN layer INTEGER default 0").stepThis().dispose(); database.executeFast("ALTER TABLE enc_chats ADD COLUMN seq_in INTEGER default 0").stepThis().dispose(); database.executeFast("ALTER TABLE enc_chats ADD COLUMN seq_out INTEGER default 0").stepThis().dispose(); @@ -1559,9 +1564,9 @@ public class MessagesStorage { } } else { if (max_id != 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid FROM media WHERE uid = %d AND mid > %d ORDER BY mid ASC LIMIT %d", uid, max_id, count)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.data, m.mid, r.random_id FROM media as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid > %d ORDER BY m.mid ASC LIMIT %d", uid, max_id, count)); } else { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid FROM media WHERE uid = %d ORDER BY mid ASC LIMIT %d,%d", uid, offset, count)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.data, m.mid, r.random_id FROM media as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d ORDER BY m.mid ASC LIMIT %d,%d", uid, offset, count)); } } @@ -1571,6 +1576,9 @@ public class MessagesStorage { TLRPC.Message message = (TLRPC.Message)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); message.id = cursor.intValue(1); message.dialog_id = uid; + if ((int)uid == 0) { + message.random_id = cursor.longValue(2); + } res.messages.add(message); fromUser.add(message.from_id); } @@ -1659,7 +1667,7 @@ public class MessagesStorage { ArrayList chatIds = new ArrayList(); ArrayList broadcastIds = new ArrayList(); ArrayList encryptedChatIds = new ArrayList(); - SQLiteCursor cursor = database.queryFinalized("SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.uid FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.mid < 0 AND m.send_state = 1 ORDER BY m.mid DESC LIMIT " + count); + SQLiteCursor cursor = database.queryFinalized("SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.uid, s.seq_in, s.seq_out FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid LEFT JOIN messages_seq as s ON m.mid = s.mid WHERE m.mid < 0 AND m.send_state = 1 ORDER BY m.mid DESC LIMIT " + count); while (cursor.next()) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(1)); if (data != null && cursor.byteBufferValue(1, data.buffer) != 0) { @@ -1671,6 +1679,8 @@ public class MessagesStorage { message.random_id = cursor.longValue(5); } message.dialog_id = cursor.longValue(6); + message.seq_in = cursor.intValue(7); + message.seq_out = cursor.intValue(8); messages.add(message); int lower_id = (int)message.dialog_id; @@ -2629,10 +2639,19 @@ public class MessagesStorage { ByteBufferDesc data = buffersStorage.getFreeBuffer(message.getObjectSize()); message.serializeToStream(data); - TLRPC.Message lastMessage = messagesMap.get(dialog_id); - if (lastMessage == null || message.date > lastMessage.date) { - messagesMap.put(dialog_id, message); + + boolean updateDialog = true; + if (message.action != null && message.action instanceof TLRPC.TL_messageEncryptedAction && !(message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL || message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages)) { + updateDialog = false; } + + if (updateDialog) { + TLRPC.Message lastMessage = messagesMap.get(dialog_id); + if (lastMessage == null || message.date > lastMessage.date) { + messagesMap.put(dialog_id, message); + } + } + state.bindInteger(1, messageId); state.bindLong(2, dialog_id); state.bindInteger(3, (MessageObject.isUnread(message) ? 0 : 1)); @@ -2820,6 +2839,25 @@ public class MessagesStorage { }); } + public void setMessageSeq(final int mid, final int seq_in, final int seq_out) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages_seq VALUES(?, ?, ?)"); + state.requery(); + state.bindInteger(1, mid); + state.bindInteger(2, seq_in); + state.bindInteger(3, seq_out); + state.step(); + state.dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + private Integer updateMessageStateAndIdInternal(long random_id, Integer _oldId, int newId, int date) { if (_oldId != null && _oldId == newId && date != 0) { SQLitePreparedStatement state = null; @@ -2835,6 +2873,7 @@ public class MessagesStorage { state.dispose(); } } + return newId; } else { Integer oldId = _oldId; @@ -2875,6 +2914,7 @@ public class MessagesStorage { } finally { if (state != null) { state.dispose(); + state = null; } } @@ -2888,6 +2928,7 @@ public class MessagesStorage { } finally { if (state != null) { state.dispose(); + state = null; } } @@ -2901,6 +2942,7 @@ public class MessagesStorage { } finally { if (state != null) { state.dispose(); + state = null; } } @@ -3113,10 +3155,63 @@ public class MessagesStorage { } try { String ids = TextUtils.join(",", messages); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT uid, data FROM messages WHERE mid IN(%s)", ids)); + ArrayList filesToDelete = new ArrayList(); + try { + while (cursor.next()) { + long did = cursor.longValue(0); + if ((int)did != 0) { + continue; + } + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(1)); + if (data != null && cursor.byteBufferValue(1, data.buffer) != 0) { + TLRPC.Message message = (TLRPC.Message)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); + if (message == null || message.media == null) { + continue; + } + if (message.media instanceof TLRPC.TL_messageMediaAudio) { + File file = FileLoader.getPathToAttach(message.media.audio); + if (file != null && file.toString().length() > 0) { + filesToDelete.add(file); + } + } else if (message.media instanceof TLRPC.TL_messageMediaPhoto) { + for (TLRPC.PhotoSize photoSize : message.media.photo.sizes) { + File file = FileLoader.getPathToAttach(photoSize); + if (file != null && file.toString().length() > 0) { + filesToDelete.add(file); + } + } + } else if (message.media instanceof TLRPC.TL_messageMediaVideo) { + File file = FileLoader.getPathToAttach(message.media.video); + if (file != null && file.toString().length() > 0) { + filesToDelete.add(file); + } + file = FileLoader.getPathToAttach(message.media.video.thumb); + if (file != null && file.toString().length() > 0) { + filesToDelete.add(file); + } + } else if (message.media instanceof TLRPC.TL_messageMediaDocument) { + File file = FileLoader.getPathToAttach(message.media.document); + if (file != null && file.toString().length() > 0) { + filesToDelete.add(file); + } + file = FileLoader.getPathToAttach(message.media.document.thumb); + if (file != null && file.toString().length() > 0) { + filesToDelete.add(file); + } + } + } + buffersStorage.reuseFreeBuffer(data); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + cursor.dispose(); + FileLoader.getInstance().deleteFiles(filesToDelete); database.executeFast(String.format(Locale.US, "DELETE FROM messages WHERE mid IN(%s)", ids)).stepThis().dispose(); + database.executeFast(String.format(Locale.US, "DELETE FROM messages_seq WHERE mid IN(%s)", ids)).stepThis().dispose(); database.executeFast(String.format(Locale.US, "DELETE FROM media WHERE mid IN(%s)", ids)).stepThis().dispose(); database.executeFast("DELETE FROM media_counts WHERE 1").stepThis().dispose(); - } catch (Exception e) { FileLog.e("tmessages", e); } diff --git a/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java index bf7f6a07..27cdd036 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java @@ -113,18 +113,18 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter if (file != null && media != null) { if (message.type == 0) { media.file = file; - performSendMessageRequest(message.sendRequest, message.obj, message.originalPath); + performSendMessageRequest(message.sendRequest, message.obj.messageOwner, message.originalPath); } else if (message.type == 1) { if (media.file == null) { media.file = file; if (media.thumb == null && message.location != null) { performSendDelayedMessage(message); } else { - performSendMessageRequest(message.sendRequest, message.obj, message.originalPath); + performSendMessageRequest(message.sendRequest, message.obj.messageOwner, message.originalPath); } } else { media.thumb = file; - performSendMessageRequest(message.sendRequest, message.obj, message.originalPath); + performSendMessageRequest(message.sendRequest, message.obj.messageOwner, message.originalPath); } } else if (message.type == 2) { if (media.file == null) { @@ -132,22 +132,22 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter if (media.thumb == null && message.location != null) { performSendDelayedMessage(message); } else { - performSendMessageRequest(message.sendRequest, message.obj, message.originalPath); + performSendMessageRequest(message.sendRequest, message.obj.messageOwner, message.originalPath); } } else { media.thumb = file; - performSendMessageRequest(message.sendRequest, message.obj, message.originalPath); + performSendMessageRequest(message.sendRequest, message.obj.messageOwner, message.originalPath); } } else if (message.type == 3) { media.file = file; - performSendMessageRequest(message.sendRequest, message.obj, message.originalPath); + performSendMessageRequest(message.sendRequest, message.obj.messageOwner, message.originalPath); } arr.remove(a); a--; } else if (encryptedFile != null && message.sendEncryptedRequest != null) { message.sendEncryptedRequest.media.key = encryptedFile.key; message.sendEncryptedRequest.media.iv = encryptedFile.iv; - performSendEncryptedRequest(message.sendEncryptedRequest, message.obj, message.encryptedChat, encryptedFile, message.originalPath, null); + performSendEncryptedRequest(message.sendEncryptedRequest, message.obj.messageOwner, message.encryptedChat, encryptedFile, message.originalPath); arr.remove(a); a--; } @@ -288,6 +288,35 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter if (messageObject.messageOwner.id >= 0) { return false; } + if (messageObject.messageOwner.action instanceof TLRPC.TL_messageEncryptedAction) { + int enc_id = (int) (messageObject.getDialogId() >> 32); + TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance().getEncryptedChat(enc_id); + if (encryptedChat == null) { + MessagesStorage.getInstance().markMessageAsSendError(messageObject.messageOwner.id); + messageObject.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, messageObject.messageOwner.id); + processSentMessage(messageObject.messageOwner.id); + return false; + } + if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { + sendTTLMessage(encryptedChat, messageObject.messageOwner); + } else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionDeleteMessages) { + sendMessagesDeleteMessage(encryptedChat, null, messageObject.messageOwner); + } else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionFlushHistory) { + sendClearHistoryMessage(encryptedChat, messageObject.messageOwner); + } else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionNotifyLayer) { + sendNotifyLayerMessage(encryptedChat, messageObject.messageOwner); + } else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionReadMessages) { + sendMessagesReadMessage(encryptedChat, null, messageObject.messageOwner); + } else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages) { + sendScreenshotMessage(encryptedChat, null, messageObject.messageOwner); + } else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionTyping) { + + } else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionResend) { + + } + return true; + } if (unsent) { unsentMessages.put(messageObject.messageOwner.id, messageObject); } @@ -623,13 +652,13 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter reqSend.message = message; reqSend.contacts = sendToPeers; reqSend.media = new TLRPC.TL_inputMediaEmpty(); - performSendMessageRequest(reqSend, newMsgObj, null); + performSendMessageRequest(reqSend, newMsgObj.messageOwner, null); } else { TLRPC.TL_messages_sendMessage reqSend = new TLRPC.TL_messages_sendMessage(); reqSend.message = message; reqSend.peer = sendToPeer; reqSend.random_id = newMsg.random_id; - performSendMessageRequest(reqSend, newMsgObj, null); + performSendMessageRequest(reqSend, newMsgObj.messageOwner, null); } } else { TLRPC.TL_decryptedMessage reqSend; @@ -644,7 +673,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter reqSend.random_id = newMsg.random_id; reqSend.message = message; reqSend.media = new TLRPC.TL_decryptedMessageMediaEmpty(); - performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null, null, null); + performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, null, null); } } else if (type >= 1 && type <= 3 || type >= 5 && type <= 8) { if (encryptedChat == null) { @@ -761,32 +790,32 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter reqSend = request; } if (type == 1) { - performSendMessageRequest(reqSend, newMsgObj, null); + performSendMessageRequest(reqSend, newMsgObj.messageOwner, null); } else if (type == 2) { if (photo.access_hash == 0) { performSendDelayedMessage(delayedMessage); } else { - performSendMessageRequest(reqSend, newMsgObj, null); + performSendMessageRequest(reqSend, newMsgObj.messageOwner, null); } } else if (type == 3) { if (video.access_hash == 0) { performSendDelayedMessage(delayedMessage); } else { - performSendMessageRequest(reqSend, newMsgObj, null); + performSendMessageRequest(reqSend, newMsgObj.messageOwner, null); } } else if (type == 6) { - performSendMessageRequest(reqSend, newMsgObj, null); + performSendMessageRequest(reqSend, newMsgObj.messageOwner, null); } else if (type == 7) { if (document.access_hash == 0) { performSendDelayedMessage(delayedMessage); } else { - performSendMessageRequest(reqSend, newMsgObj, null); + performSendMessageRequest(reqSend, newMsgObj.messageOwner, null); } } else if (type == 8) { if (audio.access_hash == 0) { performSendDelayedMessage(delayedMessage); } else { - performSendMessageRequest(reqSend, newMsgObj, null); + performSendMessageRequest(reqSend, newMsgObj.messageOwner, null); } } } else { @@ -805,7 +834,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter reqSend.media = new TLRPC.TL_decryptedMessageMediaGeoPoint(); reqSend.media.lat = lat; reqSend.media._long = lon; - performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null, null, null); + performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, null, null); } else if (type == 2) { TLRPC.PhotoSize small = photo.sizes.get(0); TLRPC.PhotoSize big = photo.sizes.get(photo.sizes.size() - 1); @@ -831,7 +860,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter encryptedFile.access_hash = big.location.secret; reqSend.media.key = big.location.key; reqSend.media.iv = big.location.iv; - performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, encryptedFile, null, null); + performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, encryptedFile, null); } } else if (type == 3) { if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { @@ -862,7 +891,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter encryptedFile.access_hash = video.access_hash; reqSend.media.key = video.key; reqSend.media.iv = video.iv; - performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, encryptedFile, null, null); + performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, encryptedFile, null); } } else if (type == 6) { reqSend.media = new TLRPC.TL_decryptedMessageMediaContact(); @@ -870,7 +899,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter reqSend.media.first_name = user.first_name; reqSend.media.last_name = user.last_name; reqSend.media.user_id = user.id; - performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null, null, null); + performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, null, null); } else if (type == 7) { reqSend.media = new TLRPC.TL_decryptedMessageMediaDocument(); reqSend.media.size = document.size; @@ -900,7 +929,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter encryptedFile.access_hash = document.access_hash; reqSend.media.key = document.key; reqSend.media.iv = document.iv; - performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, encryptedFile, null, null); + performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, encryptedFile, null); } } else if (type == 8) { if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { @@ -930,7 +959,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } else { reqSend.id = msgObj.messageOwner.fwd_msg_id; } - performSendMessageRequest(reqSend, newMsgObj, null); + performSendMessageRequest(reqSend, newMsgObj.messageOwner, null); } } catch (Exception e) { FileLog.e("tmessages", e); @@ -1046,26 +1075,26 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter }); } - private void performSendMessageRequest(final TLObject req, final MessageObject newMsgObj, final String originalPath) { + private void performSendMessageRequest(final TLObject req, final TLRPC.Message newMsgObj, final String originalPath) { ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() { @Override public void run(TLObject response, TLRPC.TL_error error) { if (error == null) { - final int oldId = newMsgObj.messageOwner.id; + final int oldId = newMsgObj.id; final boolean isBroadcast = req instanceof TLRPC.TL_messages_sendBroadcast; final ArrayList sentMessages = new ArrayList(); - final String attachPath = newMsgObj.messageOwner.attachPath; + final String attachPath = newMsgObj.attachPath; if (response instanceof TLRPC.messages_SentMessage) { TLRPC.messages_SentMessage res = (TLRPC.messages_SentMessage) response; - newMsgObj.messageOwner.id = res.id; - newMsgObj.messageOwner.date = res.date; + newMsgObj.id = res.id; + newMsgObj.date = res.date; MessagesController.getInstance().processNewDifferenceParams(res.seq, res.pts, res.date); } else if (response instanceof TLRPC.messages_StatedMessage) { TLRPC.messages_StatedMessage res = (TLRPC.messages_StatedMessage) response; sentMessages.add(res.message); - newMsgObj.messageOwner.id = res.message.id; - processSentMessage(newMsgObj.messageOwner, res.message, null, null, originalPath); + newMsgObj.id = res.message.id; + processSentMessage(newMsgObj, res.message, null, null, originalPath); MessagesController.getInstance().processNewDifferenceParams(res.seq, res.pts, res.message.date); } else if (response instanceof TLRPC.messages_StatedMessages) { TLRPC.messages_StatedMessages res = (TLRPC.messages_StatedMessages) response; @@ -1073,27 +1102,27 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter sentMessages.addAll(res.messages); TLRPC.Message message = res.messages.get(0); if (!isBroadcast) { - newMsgObj.messageOwner.id = message.id; + newMsgObj.id = message.id; } - processSentMessage(newMsgObj.messageOwner, message, null, null, originalPath); + processSentMessage(newMsgObj, message, null, null, originalPath); } MessagesController.getInstance().processNewDifferenceParams(res.seq, res.pts, -1); } MessagesStorage.getInstance().storageQueue.postRunnable(new Runnable() { @Override public void run() { - MessagesStorage.getInstance().updateMessageStateAndId(newMsgObj.messageOwner.random_id, oldId, (isBroadcast ? oldId : newMsgObj.messageOwner.id), 0, false); + MessagesStorage.getInstance().updateMessageStateAndId(newMsgObj.random_id, oldId, (isBroadcast ? oldId : newMsgObj.id), 0, false); MessagesStorage.getInstance().putMessages(sentMessages, true, false, isBroadcast, 0); if (isBroadcast) { ArrayList currentMessage = new ArrayList(); - currentMessage.add(newMsgObj.messageOwner); - newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; + currentMessage.add(newMsgObj); + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; MessagesStorage.getInstance().putMessages(currentMessage, true, false, false, 0); } AndroidUtilities.RunOnUIThread(new Runnable() { @Override public void run() { - newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; if (isBroadcast) { for (TLRPC.Message message : sentMessages) { ArrayList arr = new ArrayList(); @@ -1103,25 +1132,25 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); } - NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByServer, oldId, (isBroadcast ? oldId : newMsgObj.messageOwner.id), newMsgObj); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByServer, oldId, (isBroadcast ? oldId : newMsgObj.id), newMsgObj); processSentMessage(oldId); } }); - if (newMsgObj.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { + if (newMsgObj.media instanceof TLRPC.TL_messageMediaVideo) { stopVideoService(attachPath); } } }); } else { - MessagesStorage.getInstance().markMessageAsSendError(newMsgObj.messageOwner.id); + MessagesStorage.getInstance().markMessageAsSendError(newMsgObj.id); AndroidUtilities.RunOnUIThread(new Runnable() { @Override public void run() { - newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; - NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, newMsgObj.messageOwner.id); - processSentMessage(newMsgObj.messageOwner.id); - if (newMsgObj.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { - stopVideoService(newMsgObj.messageOwner.attachPath); + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, newMsgObj.id); + processSentMessage(newMsgObj.id); + if (newMsgObj.media instanceof TLRPC.TL_messageMediaVideo) { + stopVideoService(newMsgObj.attachPath); } } }); @@ -1130,11 +1159,11 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter }, (req instanceof TLRPC.TL_messages_forwardMessages ? null : new RPCRequest.RPCQuickAckDelegate() { @Override public void quickAck() { - final int msg_id = newMsgObj.messageOwner.id; + final int msg_id = newMsgObj.id; AndroidUtilities.RunOnUIThread(new Runnable() { @Override public void run() { - newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByAck, msg_id); } }); @@ -1142,7 +1171,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter }), true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassCanCompress, ConnectionsManager.DEFAULT_DATACENTER_ID); } - private void performSendEncryptedRequest(final TLRPC.DecryptedMessage req, final MessageObject newMsgObj, final TLRPC.EncryptedChat chat, final TLRPC.InputEncryptedFile encryptedFile, final String originalPath, final Runnable callback) { + private void performSendEncryptedRequest(final TLRPC.DecryptedMessage req, final TLRPC.Message newMsgObj, final TLRPC.EncryptedChat chat, final TLRPC.InputEncryptedFile encryptedFile, final String originalPath) { if (req == null || chat.auth_key == null || chat instanceof TLRPC.TL_encryptedChatRequested || chat instanceof TLRPC.TL_encryptedChatWaiting) { return; } @@ -1150,15 +1179,33 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 17) { TLRPC.TL_decryptedMessageLayer layer = new TLRPC.TL_decryptedMessageLayer(); layer.layer = CURRENT_SECRET_CHAT_LAYER; - layer.in_seq_no = chat.seq_in; - layer.out_seq_no = chat.seq_out; layer.message = req; layer.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))]; Utilities.random.nextBytes(layer.random_bytes); toEncryptObject = layer; - chat.seq_out += 2; - MessagesStorage.getInstance().updateEncryptedChatSeq(chat); + if (chat.seq_in == 0 && chat.seq_out == 0) { + if (chat.admin_id == UserConfig.getClientUserId()) { + chat.seq_out = 1; + } else { + chat.seq_in = 1; + } + } + + if (newMsgObj.seq_in == 0 && newMsgObj.seq_out == 0) { + layer.in_seq_no = chat.seq_in; + layer.out_seq_no = chat.seq_out; + chat.seq_out += 2; + MessagesStorage.getInstance().updateEncryptedChatSeq(chat); + if (newMsgObj != null) { + newMsgObj.seq_in = layer.in_seq_no; + newMsgObj.seq_out = layer.out_seq_no; + MessagesStorage.getInstance().setMessageSeq(newMsgObj.id, newMsgObj.seq_in, newMsgObj.seq_out); + } + } else { + layer.in_seq_no = newMsgObj.seq_in; + layer.out_seq_no = newMsgObj.seq_out; + } } else { toEncryptObject = req; } @@ -1199,13 +1246,23 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter TLObject reqToSend = null; if (encryptedFile == null) { - TLRPC.TL_messages_sendEncrypted req2 = new TLRPC.TL_messages_sendEncrypted(); - req2.data = data; - req2.random_id = req.random_id; - req2.peer = new TLRPC.TL_inputEncryptedChat(); - req2.peer.chat_id = chat.id; - req2.peer.access_hash = chat.access_hash; - reqToSend = req2; + if (req instanceof TLRPC.TL_decryptedMessageService) { + TLRPC.TL_messages_sendEncryptedService req2 = new TLRPC.TL_messages_sendEncryptedService(); + req2.data = data; + req2.random_id = req.random_id; + req2.peer = new TLRPC.TL_inputEncryptedChat(); + req2.peer.chat_id = chat.id; + req2.peer.access_hash = chat.access_hash; + reqToSend = req2; + } else { + TLRPC.TL_messages_sendEncrypted req2 = new TLRPC.TL_messages_sendEncrypted(); + req2.data = data; + req2.random_id = req.random_id; + req2.peer = new TLRPC.TL_inputEncryptedChat(); + req2.peer.chat_id = chat.id; + req2.peer.access_hash = chat.access_hash; + reqToSend = req2; + } } else { TLRPC.TL_messages_sendEncryptedFile req2 = new TLRPC.TL_messages_sendEncryptedFile(); req2.data = data; @@ -1219,28 +1276,47 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter ConnectionsManager.getInstance().performRpc(reqToSend, new RPCRequest.RPCRequestDelegate() { @Override public void run(TLObject response, TLRPC.TL_error error) { - if (error == null && callback != null) { - callback.run(); + if (error == null) { + if (req.action instanceof TLRPC.TL_decryptedMessageActionNotifyLayer) { + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + TLRPC.EncryptedChat currentChat = MessagesController.getInstance().getEncryptedChat(chat.id); + sendingNotifyLayer.remove((Integer)currentChat.id); + currentChat.layer = AndroidUtilities.setMyLayerVersion(currentChat.layer, CURRENT_SECRET_CHAT_LAYER); + MessagesStorage.getInstance().updateEncryptedChatLayer(currentChat); + } + }); + } } if (newMsgObj != null) { if (error == null) { - final String attachPath = newMsgObj.messageOwner.attachPath; + final String attachPath = newMsgObj.attachPath; final TLRPC.messages_SentEncryptedMessage res = (TLRPC.messages_SentEncryptedMessage) response; - newMsgObj.messageOwner.date = res.date; + if (newMsgObj.action instanceof TLRPC.TL_messageEncryptedAction) { + if (newMsgObj.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages || newMsgObj.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { + newMsgObj.date = res.date; + } + } if (res.file instanceof TLRPC.TL_encryptedFile) { - processSentMessage(newMsgObj.messageOwner, null, res.file, req, originalPath); + processSentMessage(newMsgObj, null, res.file, req, originalPath); } MessagesStorage.getInstance().storageQueue.postRunnable(new Runnable() { @Override public void run() { - MessagesStorage.getInstance().updateMessageStateAndId(newMsgObj.messageOwner.random_id, newMsgObj.messageOwner.id, newMsgObj.messageOwner.id, res.date, false); + if (newMsgObj.action instanceof TLRPC.TL_messageEncryptedAction) { + if (!(newMsgObj.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages || newMsgObj.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL)) { + res.date = 0; + } + } + MessagesStorage.getInstance().updateMessageStateAndId(newMsgObj.random_id, newMsgObj.id, newMsgObj.id, res.date, false); AndroidUtilities.RunOnUIThread(new Runnable() { @Override public void run() { - newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; - NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByServer, newMsgObj.messageOwner.id, newMsgObj.messageOwner.id, newMsgObj); - processSentMessage(newMsgObj.messageOwner.id); - if (newMsgObj.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByServer, newMsgObj.id, newMsgObj.id, newMsgObj); + processSentMessage(newMsgObj.id); + if (newMsgObj.media instanceof TLRPC.TL_messageMediaVideo) { stopVideoService(attachPath); } } @@ -1248,15 +1324,15 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } }); } else { - MessagesStorage.getInstance().markMessageAsSendError(newMsgObj.messageOwner.id); + MessagesStorage.getInstance().markMessageAsSendError(newMsgObj.id); AndroidUtilities.RunOnUIThread(new Runnable() { @Override public void run() { - newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; - NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, newMsgObj.messageOwner.id); - processSentMessage(newMsgObj.messageOwner.id); - if (newMsgObj.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { - stopVideoService(newMsgObj.messageOwner.attachPath); + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, newMsgObj.id); + processSentMessage(newMsgObj.id); + if (newMsgObj.media instanceof TLRPC.TL_messageMediaVideo) { + stopVideoService(newMsgObj.attachPath); } } }); @@ -1492,7 +1568,38 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } } - public void sendMessagesReadMessage(ArrayList random_ids, TLRPC.EncryptedChat encryptedChat) { + private TLRPC.TL_messageService createServiceSecretMessage(final TLRPC.EncryptedChat encryptedChat, TLRPC.DecryptedMessageAction decryptedMessage) { + TLRPC.TL_messageService newMsg = new TLRPC.TL_messageService(); + + newMsg.action = new TLRPC.TL_messageEncryptedAction(); + newMsg.action.encryptedAction = decryptedMessage; + newMsg.local_id = newMsg.id = UserConfig.getNewMessageId(); + newMsg.from_id = UserConfig.getClientUserId(); + newMsg.flags = TLRPC.MESSAGE_FLAG_UNREAD | TLRPC.MESSAGE_FLAG_OUT; + newMsg.dialog_id = ((long)encryptedChat.id) << 32; + newMsg.to_id = new TLRPC.TL_peerUser(); + newMsg.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING; + if (encryptedChat.participant_id == UserConfig.getClientUserId()) { + newMsg.to_id.user_id = encryptedChat.admin_id; + } else { + newMsg.to_id.user_id = encryptedChat.participant_id; + } + if (decryptedMessage instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages || decryptedMessage instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { + newMsg.date = ConnectionsManager.getInstance().getCurrentTime(); + } else { + newMsg.date = 0; + } + newMsg.random_id = getNextRandomId(); + UserConfig.saveConfig(false); + + ArrayList arr = new ArrayList(); + arr.add(newMsg); + MessagesStorage.getInstance().putMessages(arr, false, true, true, 0); + + return newMsg; + } + + public void sendMessagesReadMessage(TLRPC.EncryptedChat encryptedChat, ArrayList random_ids, TLRPC.Message resendMessage) { if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { return; } @@ -1504,13 +1611,23 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))]; Utilities.random.nextBytes(reqSend.random_bytes); } - reqSend.random_id = getNextRandomId(); - reqSend.action = new TLRPC.TL_decryptedMessageActionReadMessages(); - reqSend.action.random_ids = random_ids; - performSendEncryptedRequest(reqSend, null, encryptedChat, null, null, null); + + TLRPC.Message message = null; + + if (resendMessage != null) { + message = resendMessage; + reqSend.action = message.action.encryptedAction; + } else { + reqSend.action = new TLRPC.TL_decryptedMessageActionReadMessages(); + reqSend.action.random_ids = random_ids; + message = createServiceSecretMessage(encryptedChat, reqSend.action); + } + reqSend.random_id = message.random_id; + + performSendEncryptedRequest(reqSend, message, encryptedChat, null, null); } - public void sendMessagesDeleteMessage(ArrayList random_ids, TLRPC.EncryptedChat encryptedChat) { + public void sendMessagesDeleteMessage(TLRPC.EncryptedChat encryptedChat, ArrayList random_ids, TLRPC.Message resendMessage) { if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { return; } @@ -1522,13 +1639,23 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))]; Utilities.random.nextBytes(reqSend.random_bytes); } - reqSend.random_id = getNextRandomId(); - reqSend.action = new TLRPC.TL_decryptedMessageActionDeleteMessages(); - reqSend.action.random_ids = random_ids; - performSendEncryptedRequest(reqSend, null, encryptedChat, null, null, null); + + TLRPC.Message message = null; + + if (resendMessage != null) { + message = resendMessage; + reqSend.action = message.action.encryptedAction; + } else { + reqSend.action = new TLRPC.TL_decryptedMessageActionDeleteMessages(); + reqSend.action.random_ids = random_ids; + message = createServiceSecretMessage(encryptedChat, reqSend.action); + } + reqSend.random_id = message.random_id; + + performSendEncryptedRequest(reqSend, message, encryptedChat, null, null); } - public void sendClearHistoryMessage(TLRPC.EncryptedChat encryptedChat) { + public void sendClearHistoryMessage(TLRPC.EncryptedChat encryptedChat, TLRPC.Message resendMessage) { if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { return; } @@ -1540,12 +1667,22 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))]; Utilities.random.nextBytes(reqSend.random_bytes); } - reqSend.random_id = getNextRandomId(); - reqSend.action = new TLRPC.TL_decryptedMessageActionFlushHistory(); - performSendEncryptedRequest(reqSend, null, encryptedChat, null, null, null); + + TLRPC.Message message = null; + + if (resendMessage != null) { + message = resendMessage; + reqSend.action = message.action.encryptedAction; + } else { + reqSend.action = new TLRPC.TL_decryptedMessageActionFlushHistory(); + message = createServiceSecretMessage(encryptedChat, reqSend.action); + } + reqSend.random_id = message.random_id; + + performSendEncryptedRequest(reqSend, message, encryptedChat, null, null); } - public void sendNotifyLayerMessage(final TLRPC.EncryptedChat encryptedChat) { + public void sendNotifyLayerMessage(final TLRPC.EncryptedChat encryptedChat, TLRPC.Message resendMessage) { if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { return; } @@ -1561,57 +1698,26 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))]; Utilities.random.nextBytes(reqSend.random_bytes); } - reqSend.random_id = getNextRandomId(); - reqSend.action = new TLRPC.TL_decryptedMessageActionNotifyLayer(); - reqSend.action.layer = CURRENT_SECRET_CHAT_LAYER; - Runnable callback = new Runnable() { - @Override - public void run() { - AndroidUtilities.RunOnUIThread(new Runnable() { - @Override - public void run() { - TLRPC.EncryptedChat chat = MessagesController.getInstance().getEncryptedChat(encryptedChat.id); - sendingNotifyLayer.remove((Integer)chat.id); - chat.layer = AndroidUtilities.setMyLayerVersion(chat.layer, CURRENT_SECRET_CHAT_LAYER); - MessagesStorage.getInstance().updateEncryptedChatLayer(chat); - } - }); - } - }; - performSendEncryptedRequest(reqSend, null, encryptedChat, null, null, callback); + + TLRPC.Message message = null; + + if (resendMessage != null) { + message = resendMessage; + reqSend.action = message.action.encryptedAction; + } else { + reqSend.action = new TLRPC.TL_decryptedMessageActionNotifyLayer(); + reqSend.action.layer = CURRENT_SECRET_CHAT_LAYER; + message = createServiceSecretMessage(encryptedChat, reqSend.action); + } + reqSend.random_id = message.random_id; + + performSendEncryptedRequest(reqSend, message, encryptedChat, null, null); } - public void sendTTLMessage(TLRPC.EncryptedChat encryptedChat) { + public void sendTTLMessage(TLRPC.EncryptedChat encryptedChat, TLRPC.Message resendMessage) { if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { return; } - TLRPC.TL_messageService newMsg = new TLRPC.TL_messageService(); - - newMsg.action = new TLRPC.TL_messageActionTTLChange(); - newMsg.action.ttl = encryptedChat.ttl; - newMsg.local_id = newMsg.id = UserConfig.getNewMessageId(); - newMsg.from_id = UserConfig.getClientUserId(); - newMsg.flags = TLRPC.MESSAGE_FLAG_UNREAD | TLRPC.MESSAGE_FLAG_OUT; - newMsg.dialog_id = ((long)encryptedChat.id) << 32; - newMsg.to_id = new TLRPC.TL_peerUser(); - if (encryptedChat.participant_id == UserConfig.getClientUserId()) { - newMsg.to_id.user_id = encryptedChat.admin_id; - } else { - newMsg.to_id.user_id = encryptedChat.participant_id; - } - newMsg.date = ConnectionsManager.getInstance().getCurrentTime(); - newMsg.random_id = getNextRandomId(); - UserConfig.saveConfig(false); - final MessageObject newMsgObj = new MessageObject(newMsg, null); - newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING; - - final ArrayList objArr = new ArrayList(); - objArr.add(newMsgObj); - ArrayList arr = new ArrayList(); - arr.add(newMsg); - MessagesStorage.getInstance().putMessages(arr, false, true, false, 0); - MessagesController.getInstance().updateInterfaceWithMessages(newMsg.dialog_id, objArr); - NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); TLRPC.TL_decryptedMessageService reqSend = null; if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { @@ -1621,49 +1727,34 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))]; Utilities.random.nextBytes(reqSend.random_bytes); } - reqSend.random_id = newMsg.random_id; - reqSend.action = new TLRPC.TL_decryptedMessageActionSetMessageTTL(); - reqSend.action.ttl_seconds = encryptedChat.ttl; - performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null, null, null); + + TLRPC.Message message = null; + + if (resendMessage != null) { + message = resendMessage; + reqSend.action = message.action.encryptedAction; + } else { + reqSend.action = new TLRPC.TL_decryptedMessageActionSetMessageTTL(); + reqSend.action.ttl_seconds = encryptedChat.ttl; + message = createServiceSecretMessage(encryptedChat, reqSend.action); + + MessageObject newMsgObj = new MessageObject(message, null); + newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING; + ArrayList objArr = new ArrayList(); + objArr.add(newMsgObj); + MessagesController.getInstance().updateInterfaceWithMessages(message.dialog_id, objArr); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + } + reqSend.random_id = message.random_id; + + performSendEncryptedRequest(reqSend, message, encryptedChat, null, null); } - public void sendScreenshotMessage(TLRPC.EncryptedChat encryptedChat, ArrayList random_ids) { + public void sendScreenshotMessage(TLRPC.EncryptedChat encryptedChat, ArrayList random_ids, TLRPC.Message resendMessage) { if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { return; } - TLRPC.TL_decryptedMessageActionScreenshotMessages action = new TLRPC.TL_decryptedMessageActionScreenshotMessages(); - action.random_ids = random_ids; - - TLRPC.TL_messageService newMsg = new TLRPC.TL_messageService(); - - newMsg.action = new TLRPC.TL_messageEcryptedAction(); - newMsg.action.encryptedAction = action; - - newMsg.local_id = newMsg.id = UserConfig.getNewMessageId(); - newMsg.from_id = UserConfig.getClientUserId(); - newMsg.flags = TLRPC.MESSAGE_FLAG_UNREAD | TLRPC.MESSAGE_FLAG_OUT; - newMsg.dialog_id = ((long)encryptedChat.id) << 32; - newMsg.to_id = new TLRPC.TL_peerUser(); - if (encryptedChat.participant_id == UserConfig.getClientUserId()) { - newMsg.to_id.user_id = encryptedChat.admin_id; - } else { - newMsg.to_id.user_id = encryptedChat.participant_id; - } - newMsg.date = ConnectionsManager.getInstance().getCurrentTime(); - newMsg.random_id = getNextRandomId(); - UserConfig.saveConfig(false); - final MessageObject newMsgObj = new MessageObject(newMsg, null); - newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING; - - final ArrayList objArr = new ArrayList(); - objArr.add(newMsgObj); - ArrayList arr = new ArrayList(); - arr.add(newMsg); - MessagesStorage.getInstance().putMessages(arr, false, true, false, 0); - MessagesController.getInstance().updateInterfaceWithMessages(newMsg.dialog_id, objArr); - NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); - TLRPC.TL_decryptedMessageService reqSend = null; if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { reqSend = new TLRPC.TL_decryptedMessageService(); @@ -1672,9 +1763,27 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))]; Utilities.random.nextBytes(reqSend.random_bytes); } - reqSend.random_id = newMsg.random_id; - reqSend.action = action; - performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null, null, null); + + TLRPC.Message message = null; + + if (resendMessage != null) { + message = resendMessage; + reqSend.action = message.action.encryptedAction; + } else { + reqSend.action = new TLRPC.TL_decryptedMessageActionScreenshotMessages(); + reqSend.action.random_ids = random_ids; + message = createServiceSecretMessage(encryptedChat, reqSend.action); + + MessageObject newMsgObj = new MessageObject(message, null); + newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING; + ArrayList objArr = new ArrayList(); + objArr.add(newMsgObj); + MessagesController.getInstance().updateInterfaceWithMessages(message.dialog_id, objArr); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + } + reqSend.random_id = message.random_id; + + performSendEncryptedRequest(reqSend, message, encryptedChat, null, null); } private void putToDelayedMessages(String location, DelayedMessage message) { @@ -1695,7 +1804,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } public void checkUnsentMessages() { - MessagesStorage.getInstance().getUnsentMessages(10); + MessagesStorage.getInstance().getUnsentMessages(1000); } protected void processUnsentMessages(final ArrayList messages, final ArrayList users, final ArrayList chats, final ArrayList encryptedChats) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java index be06766b..0a134c09 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java @@ -704,4 +704,26 @@ public class FileLoader { } return ""; } + + public void deleteFiles(final ArrayList files) { + if (files == null || files.isEmpty()) { + return; + } + fileLoaderQueue.postRunnable(new Runnable() { + @Override + public void run() { + for (File file : files) { + if (file.exists()) { + try { + if (!file.delete()) { + file.deleteOnExit(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + } + }); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TLClassStore.java b/TMessagesProj/src/main/java/org/telegram/messenger/TLClassStore.java index 67a050c2..aa690ca1 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TLClassStore.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TLClassStore.java @@ -370,7 +370,7 @@ public class TLClassStore { classStore.put(TLRPC.TL_userRequest_old.constructor, TLRPC.TL_userRequest_old.class); classStore.put(TLRPC.TL_userForeign_old.constructor, TLRPC.TL_userForeign_old.class); classStore.put(TLRPC.TL_userDeleted_old.constructor, TLRPC.TL_userDeleted_old.class); - classStore.put(TLRPC.TL_messageEcryptedAction.constructor, TLRPC.TL_messageEcryptedAction.class); + classStore.put(TLRPC.TL_messageEncryptedAction.constructor, TLRPC.TL_messageEncryptedAction.class); } static TLClassStore store = null; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java index b358aca1..af8559cb 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java @@ -8429,33 +8429,38 @@ public class TLRPC { } } + //manually created + public static class TL_messages_sendEncryptedService extends TLObject { public static int constructor = 0x32d439a4; public TL_inputEncryptedChat peer; public long random_id; - public byte[] data; + public ByteBufferDesc data; public Class responseClass () { return messages_SentEncryptedMessage.class; } - public void readParams(AbsSerializedData stream) { - peer = (TL_inputEncryptedChat)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); - random_id = stream.readInt64(); - data = stream.readByteArray(); - } - public void serializeToStream(AbsSerializedData stream) { stream.writeInt32(constructor); peer.serializeToStream(stream); stream.writeInt64(random_id); - stream.writeByteArray(data); + stream.writeByteBuffer(data); + } + + @Override + public void freeResources() { + if (disableFree) { + return; + } + if (data != null) { + BuffersStorage.getInstance().reuseFreeBuffer(data); + data = null; + } } } - //manually created - public static class TL_userDeleted_old extends TL_userDeleted { public static int constructor = 0xb29ad7cc; @@ -8990,6 +8995,8 @@ public class TLRPC { public int ttl; public int destroyTime; public int layer; + public int seq_in; + public int seq_out; public VideoEditedInfo videoEditedInfo = null; } @@ -9993,7 +10000,7 @@ public class TLRPC { } } - public static class TL_messageEcryptedAction extends MessageAction { + public static class TL_messageEncryptedAction extends MessageAction { public static int constructor = 0x555555F7; public void readParams(AbsSerializedData stream) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java index 7a9e7bbc..a28e59ba 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -43,36 +43,41 @@ public class ChatMessageCell extends ChatBaseCell { y -= textY; int blockNum = Math.max(0, y / currentMessageObject.blockHeight); if (blockNum < currentMessageObject.textLayoutBlocks.size()) { - MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(blockNum); - x -= textX - (int)Math.ceil(block.textXOffset); - y -= block.textYOffset; - final int line = block.textLayout.getLineForVertical(y); - final int off = block.textLayout.getOffsetForHorizontal(line, x) + block.charactersOffset; + try { + MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(blockNum); + x -= textX - (int)Math.ceil(block.textXOffset); + y -= block.textYOffset; + final int line = block.textLayout.getLineForVertical(y); + final int off = block.textLayout.getOffsetForHorizontal(line, x) + block.charactersOffset; - final float left = block.textLayout.getLineLeft(line); - if (left <= x && left + block.textLayout.getLineWidth(line) >= x) { - Spannable buffer = (Spannable)currentMessageObject.messageText; - ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); + final float left = block.textLayout.getLineLeft(line); + if (left <= x && left + block.textLayout.getLineWidth(line) >= x) { + Spannable buffer = (Spannable)currentMessageObject.messageText; + ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); - if (link.length != 0) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - pressedLink = link[0]; - return true; - } else { - if (link[0] == pressedLink) { - try { - pressedLink.onClick(this); - } catch (Exception e) { - FileLog.e("tmessages", e); - } + if (link.length != 0) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + pressedLink = link[0]; return true; + } else { + if (link[0] == pressedLink) { + try { + pressedLink.onClick(this); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return true; + } } + } else { + pressedLink = null; } } else { pressedLink = null; } - } else { + } catch (Exception e) { pressedLink = null; + FileLog.e("tmessages", e); } } else { pressedLink = null; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 7d507479..e5918f4b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -387,7 +387,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not typingDotsDrawable.setIsChat(currentChat != null); if (currentEncryptedChat != null && AndroidUtilities.getMyLayerVersion(currentEncryptedChat.layer) != SendMessagesHelper.CURRENT_SECRET_CHAT_LAYER) { - SendMessagesHelper.getInstance().sendNotifyLayerMessage(currentEncryptedChat); + SendMessagesHelper.getInstance().sendNotifyLayerMessage(currentEncryptedChat, null); } return true; @@ -651,7 +651,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not actionModeViews.clear(); - ActionBarMenu actionMode = actionBarLayer.createActionMode(); + final ActionBarMenu actionMode = actionBarLayer.createActionMode(); actionModeViews.add(actionMode.addItem(-2, R.drawable.ic_ab_done_gray, R.drawable.bar_selector_mode)); FrameLayout layout = new FrameLayout(actionMode.getContext()); @@ -822,6 +822,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatListView.setOnInterceptTouchEventListener(new LayoutListView.OnInterceptTouchEventListener() { @Override public boolean onInterceptTouchEvent(MotionEvent event) { + if (actionBarLayer.isActionModeShowed()) { + return false; + } if (event.getAction() == MotionEvent.ACTION_DOWN) { int x = (int)event.getX(); int y = (int)event.getY(); @@ -880,14 +883,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not public boolean onTouch(View v, MotionEvent event) { if (openSecretPhotoRunnable != null || SecretPhotoViewer.getInstance().isVisible()) { if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_POINTER_UP) { + AndroidUtilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + chatListView.setOnItemClickListener(onItemClickListener); + } + }, 150); if (openSecretPhotoRunnable != null) { AndroidUtilities.CancelRunOnUIThread(openSecretPhotoRunnable); - AndroidUtilities.RunOnUIThread(new Runnable() { - @Override - public void run() { - chatListView.setOnItemClickListener(onItemClickListener); - } - }, 150); openSecretPhotoRunnable = null; try { Toast.makeText(v.getContext(), LocaleController.getString("PhotoTip", R.string.PhotoTip), Toast.LENGTH_SHORT).show(); @@ -899,14 +902,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not AndroidUtilities.RunOnUIThread(new Runnable() { @Override public void run() { - chatListView.setOnItemClickListener(onItemClickListener); chatListView.setOnItemLongClickListener(onItemLongClickListener); chatListView.setLongClickable(true); } }); SecretPhotoViewer.getInstance().closePhoto(); - } else { - chatListView.setOnItemClickListener(onItemClickListener); } } } else if (event.getAction() != MotionEvent.ACTION_DOWN) { @@ -1043,7 +1043,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (messageObject == null || messageObject.isOut() || !messageObject.isSecretMedia() || messageObject.messageOwner.destroyTime != 0) { return false; } - MessagesController.getInstance().markMessageAsRead(dialog_id, messageObject.messageOwner.random_id); + MessagesController.getInstance().markMessageAsRead(dialog_id, messageObject.messageOwner.random_id, messageObject.messageOwner.ttl); messageObject.messageOwner.destroyTime = messageObject.messageOwner.ttl + ConnectionsManager.getInstance().getCurrentTime(); return true; } @@ -1290,11 +1290,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { return 6; } - } else if (messageObject.type == 10 || messageObject.type == 11 || messageObject.isSending()) { - if (messageObject.messageOwner.id == 0) { + } else if (messageObject.type == 10 || messageObject.type == 11) { + if (messageObject.isSending()) { return -1; + } else { + return 1; } - return 1; } else { if (!(messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaEmpty)) { if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVideo || @@ -1502,10 +1503,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not SendMessagesHelper.prepareSendingVideo(videoPath, estimatedSize, estimatedDuration, resultWidth, resultHeight, videoEditedInfo, dialog_id); } }); - if (parentLayout == null || !parentLayout.presentFragment(fragment, removeLast, true, true)) { + + if (parentLayout == null || !fragment.onFragmentCreate()) { SendMessagesHelper.prepareSendingVideo(videoPath, 0, 0, 0, 0, null, dialog_id); return false; } + parentLayout.presentFragment(fragment, removeLast, true, true); return true; } @@ -1686,6 +1689,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (minDate == 0 || obj.messageOwner.date < minDate) { minDate = obj.messageOwner.date; } + + if (obj.type < 0) { + continue; + } + if (!obj.isOut() && obj.isUnread()) { wasUnread = true; } @@ -1876,14 +1884,18 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ArrayList arr = (ArrayList)args[1]; if (currentEncryptedChat != null && arr.size() == 1) { - MessageObject messageObject = arr.get(0); + MessageObject obj = arr.get(0); - if (messageObject.isOut() && messageObject.messageOwner.action instanceof TLRPC.TL_messageActionTTLChange && getParentActivity() != null && AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) < 17 && currentEncryptedChat.ttl > 0 && currentEncryptedChat.ttl <= 60) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(R.string.OK, null); - builder.setMessage(LocaleController.formatString("CompatibilityChat", R.string.CompatibilityChat, currentUser.first_name, currentUser.first_name)); - showAlertDialog(builder); + if (currentEncryptedChat != null && obj.isOut() && obj.messageOwner.action != null && obj.messageOwner.action instanceof TLRPC.TL_messageEncryptedAction && + obj.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL && getParentActivity() != null) { + TLRPC.TL_decryptedMessageActionSetMessageTTL action = (TLRPC.TL_decryptedMessageActionSetMessageTTL)obj.messageOwner.action.encryptedAction; + if (AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) < 17 && currentEncryptedChat.ttl > 0 && currentEncryptedChat.ttl <= 60) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(R.string.OK, null); + builder.setMessage(LocaleController.formatString("CompatibilityChat", R.string.CompatibilityChat, currentUser.first_name, currentUser.first_name)); + showAlertDialog(builder); + } } } @@ -1896,8 +1908,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not boolean currentMarkAsRead = false; for (MessageObject obj : arr) { - if (currentEncryptedChat != null && obj.messageOwner.action != null && obj.messageOwner.action instanceof TLRPC.TL_messageActionTTLChange && timerButton != null) { - timerButton.setTime(obj.messageOwner.action.ttl); + if (currentEncryptedChat != null && obj.messageOwner.action != null && obj.messageOwner.action instanceof TLRPC.TL_messageEncryptedAction && + obj.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL && timerButton != null) { + TLRPC.TL_decryptedMessageActionSetMessageTTL action = (TLRPC.TL_decryptedMessageActionSetMessageTTL)obj.messageOwner.action.encryptedAction; + timerButton.setTime(action.ttl_seconds); } if (obj.isOut() && obj.isSending()) { scrollToLastMessage(); @@ -1938,8 +1952,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not boolean markAsRead = false; int oldCount = messages.size(); for (MessageObject obj : arr) { - if (currentEncryptedChat != null && obj.messageOwner.action != null && obj.messageOwner.action instanceof TLRPC.TL_messageActionTTLChange && timerButton != null) { - timerButton.setTime(obj.messageOwner.action.ttl); + if (currentEncryptedChat != null && obj.messageOwner.action != null && obj.messageOwner.action instanceof TLRPC.TL_messageEncryptedAction && + obj.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL && timerButton != null) { + TLRPC.TL_decryptedMessageActionSetMessageTTL action = (TLRPC.TL_decryptedMessageActionSetMessageTTL)obj.messageOwner.action.encryptedAction; + timerButton.setTime(action.ttl_seconds); } if (messagesDict.containsKey(obj.messageOwner.id)) { continue; @@ -2108,9 +2124,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not MessageObject obj = messagesDict.get(msgId); if (obj != null) { Integer newMsgId = (Integer)args[1]; - MessageObject newMsgObj = (MessageObject)args[2]; + TLRPC.Message newMsgObj = (TLRPC.Message)args[2]; if (newMsgObj != null) { - obj.messageOwner.media = newMsgObj.messageOwner.media; + obj.messageOwner.media = newMsgObj.media; obj.generateThumbs(true, 1); } messagesDict.remove(msgId); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index 3e70e6b9..a0a34961 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -657,7 +657,16 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (obj.isSent()) { ArrayList arr = new ArrayList(); arr.add(obj.messageOwner.id); - MessagesController.getInstance().deleteMessages(arr, null, null); + + ArrayList random_ids = null; + TLRPC.EncryptedChat encryptedChat = null; + if ((int)obj.getDialogId() == 0 && obj.messageOwner.random_id != 0) { + random_ids = new ArrayList(); + random_ids.add(obj.messageOwner.random_id); + encryptedChat = MessagesController.getInstance().getEncryptedChat((int)(obj.getDialogId() >> 32)); + } + + MessagesController.getInstance().deleteMessages(arr, random_ids, encryptedChat); closePhoto(false); } } else if (!avatarsArr.isEmpty()) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java index f6cb32d1..9a417704 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java @@ -71,9 +71,7 @@ public class SettingsChangeUsernameActivity extends BaseFragment { doneButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - if (firstNameField.getText().length() != 0) { - saveName(); - } + saveName(); } }); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/VideoEditorActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/VideoEditorActivity.java index 1de73843..6a9c7027 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/VideoEditorActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/VideoEditorActivity.java @@ -58,6 +58,7 @@ import java.util.List; @TargetApi(16) public class VideoEditorActivity extends BaseFragment implements TextureView.SurfaceTextureListener { + private boolean created = false; private MediaPlayer videoPlayer = null; private VideoTimelineView videoTimelineView = null; private View videoContainerView = null; @@ -161,6 +162,9 @@ public class VideoEditorActivity extends BaseFragment implements TextureView.Sur @Override public boolean onFragmentCreate() { + if (created) { + return true; + } if (videoPath == null || !processOpenVideo()) { return false; } @@ -191,6 +195,8 @@ public class VideoEditorActivity extends BaseFragment implements TextureView.Sur return false; } + created = true; + return super.onFragmentCreate(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/NumberPicker.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/NumberPicker.java index e91a7113..bd5e23b2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/NumberPicker.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/NumberPicker.java @@ -36,7 +36,6 @@ import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.animation.DecelerateInterpolator; import android.widget.LinearLayout; -import android.widget.Scroller; import android.widget.TextView; import org.telegram.messenger.R; @@ -726,6 +725,28 @@ public class NumberPicker extends LinearLayout { } } + public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { + int result = size; + int specMode = MeasureSpec.getMode(measureSpec); + int specSize = MeasureSpec.getSize(measureSpec); + switch (specMode) { + case MeasureSpec.UNSPECIFIED: + result = size; + break; + case MeasureSpec.AT_MOST: + if (specSize < size) { + result = specSize | 16777216; + } else { + result = size; + } + break; + case MeasureSpec.EXACTLY: + result = specSize; + break; + } + return result | (childMeasuredState & (-16777216)); + } + private void initializeSelectorWheelIndices() { mSelectorIndexToStringCache.clear(); int[] selectorIndices = mSelectorIndices; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/Scroller.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/Scroller.java new file mode 100644 index 00000000..b87b9b7c --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/Scroller.java @@ -0,0 +1,502 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.ui.Views; + +import android.content.Context; +import android.hardware.SensorManager; +import android.util.FloatMath; +import android.view.ViewConfiguration; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; + + +/** + * This class encapsulates scrolling. The duration of the scroll + * can be passed in the constructor and specifies the maximum time that + * the scrolling animation should take. Past this time, the scrolling is + * automatically moved to its final stage and computeScrollOffset() + * will always return false to indicate that scrolling is over. + */ +public class Scroller { + private int mMode; + + private int mStartX; + private int mStartY; + private int mFinalX; + private int mFinalY; + + private int mMinX; + private int mMaxX; + private int mMinY; + private int mMaxY; + + private int mCurrX; + private int mCurrY; + private long mStartTime; + private int mDuration; + private float mDurationReciprocal; + private float mDeltaX; + private float mDeltaY; + private boolean mFinished; + private Interpolator mInterpolator; + private boolean mFlywheel; + + private float mVelocity; + + private static final int DEFAULT_DURATION = 250; + private static final int SCROLL_MODE = 0; + private static final int FLING_MODE = 1; + + private static float DECELERATION_RATE = (float) (Math.log(0.75) / Math.log(0.9)); + private static float START_TENSION = 0.4f; // Tension at start: (0.4 * total T, 1.0 * Distance) + private static float END_TENSION = 1.0f - START_TENSION; + private static final int NB_SAMPLES = 100; + private static final float[] SPLINE = new float[NB_SAMPLES + 1]; + + private float mDeceleration; + private final float mPpi; + + static { + float x_min = 0.0f; + for (int i = 0; i <= NB_SAMPLES; i++) { + final float t = (float) i / NB_SAMPLES; + float x_max = 1.0f; + float x, tx, coef; + while (true) { + x = x_min + (x_max - x_min) / 2.0f; + coef = 3.0f * x * (1.0f - x); + tx = coef * ((1.0f - x) * START_TENSION + x * END_TENSION) + x * x * x; + if (Math.abs(tx - t) < 1E-5) break; + if (tx > t) x_max = x; + else x_min = x; + } + final float d = coef + x * x * x; + SPLINE[i] = d; + } + SPLINE[NB_SAMPLES] = 1.0f; + + // This controls the viscous fluid effect (how much of it) + sViscousFluidScale = 8.0f; + // must be set to 1.0 (used in viscousFluid()) + sViscousFluidNormalize = 1.0f; + sViscousFluidNormalize = 1.0f / viscousFluid(1.0f); + } + + private static float sViscousFluidScale; + private static float sViscousFluidNormalize; + + /** + * Create a Scroller with the default duration and interpolator. + */ + public Scroller(Context context) { + this(context, null); + } + + /** + * Create a Scroller with the specified interpolator. If the interpolator is + * null, the default (viscous) interpolator will be used. "Flywheel" behavior will + * be in effect for apps targeting Honeycomb or newer. + */ + public Scroller(Context context, Interpolator interpolator) { + this(context, interpolator, true); + } + + /** + * Create a Scroller with the specified interpolator. If the interpolator is + * null, the default (viscous) interpolator will be used. Specify whether or + * not to support progressive "flywheel" behavior in flinging. + */ + public Scroller(Context context, Interpolator interpolator, boolean flywheel) { + mFinished = true; + mInterpolator = interpolator; + mPpi = context.getResources().getDisplayMetrics().density * 160.0f; + mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction()); + mFlywheel = flywheel; + } + + /** + * The amount of friction applied to flings. The default value + * is {@link android.view.ViewConfiguration#getScrollFriction}. + * + * @param friction A scalar dimension-less value representing the coefficient of + * friction. + */ + public final void setFriction(float friction) { + mDeceleration = computeDeceleration(friction); + } + + private float computeDeceleration(float friction) { + return SensorManager.GRAVITY_EARTH // g (m/s^2) + * 39.37f // inch/meter + * mPpi // pixels per inch + * friction; + } + + /** + * + * Returns whether the scroller has finished scrolling. + * + * @return True if the scroller has finished scrolling, false otherwise. + */ + public final boolean isFinished() { + return mFinished; + } + + /** + * Force the finished field to a particular value. + * + * @param finished The new finished value. + */ + public final void forceFinished(boolean finished) { + mFinished = finished; + } + + /** + * Returns how long the scroll event will take, in milliseconds. + * + * @return The duration of the scroll in milliseconds. + */ + public final int getDuration() { + return mDuration; + } + + /** + * Returns the current X offset in the scroll. + * + * @return The new X offset as an absolute distance from the origin. + */ + public final int getCurrX() { + return mCurrX; + } + + /** + * Returns the current Y offset in the scroll. + * + * @return The new Y offset as an absolute distance from the origin. + */ + public final int getCurrY() { + return mCurrY; + } + + /** + * Returns the current velocity. + * + * @return The original velocity less the deceleration. Result may be + * negative. + */ + public float getCurrVelocity() { + return mVelocity - mDeceleration * timePassed() / 2000.0f; + } + + /** + * Returns the start X offset in the scroll. + * + * @return The start X offset as an absolute distance from the origin. + */ + public final int getStartX() { + return mStartX; + } + + /** + * Returns the start Y offset in the scroll. + * + * @return The start Y offset as an absolute distance from the origin. + */ + public final int getStartY() { + return mStartY; + } + + /** + * Returns where the scroll will end. Valid only for "fling" scrolls. + * + * @return The final X offset as an absolute distance from the origin. + */ + public final int getFinalX() { + return mFinalX; + } + + /** + * Returns where the scroll will end. Valid only for "fling" scrolls. + * + * @return The final Y offset as an absolute distance from the origin. + */ + public final int getFinalY() { + return mFinalY; + } + + /** + * Call this when you want to know the new location. If it returns true, + * the animation is not yet finished. loc will be altered to provide the + * new location. + */ + public boolean computeScrollOffset() { + if (mFinished) { + return false; + } + + int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime); + + if (timePassed < mDuration) { + switch (mMode) { + case SCROLL_MODE: + float x = timePassed * mDurationReciprocal; + + if (mInterpolator == null) + x = viscousFluid(x); + else + x = mInterpolator.getInterpolation(x); + + mCurrX = mStartX + Math.round(x * mDeltaX); + mCurrY = mStartY + Math.round(x * mDeltaY); + break; + case FLING_MODE: + final float t = (float) timePassed / mDuration; + final int index = (int) (NB_SAMPLES * t); + final float t_inf = (float) index / NB_SAMPLES; + final float t_sup = (float) (index + 1) / NB_SAMPLES; + final float d_inf = SPLINE[index]; + final float d_sup = SPLINE[index + 1]; + final float distanceCoef = d_inf + (t - t_inf) / (t_sup - t_inf) * (d_sup - d_inf); + + mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX)); + // Pin to mMinX <= mCurrX <= mMaxX + mCurrX = Math.min(mCurrX, mMaxX); + mCurrX = Math.max(mCurrX, mMinX); + + mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY)); + // Pin to mMinY <= mCurrY <= mMaxY + mCurrY = Math.min(mCurrY, mMaxY); + mCurrY = Math.max(mCurrY, mMinY); + + if (mCurrX == mFinalX && mCurrY == mFinalY) { + mFinished = true; + } + + break; + } + } + else { + mCurrX = mFinalX; + mCurrY = mFinalY; + mFinished = true; + } + return true; + } + + /** + * Start scrolling by providing a starting point and the distance to travel. + * The scroll will use the default value of 250 milliseconds for the + * duration. + * + * @param startX Starting horizontal scroll offset in pixels. Positive + * numbers will scroll the content to the left. + * @param startY Starting vertical scroll offset in pixels. Positive numbers + * will scroll the content up. + * @param dx Horizontal distance to travel. Positive numbers will scroll the + * content to the left. + * @param dy Vertical distance to travel. Positive numbers will scroll the + * content up. + */ + public void startScroll(int startX, int startY, int dx, int dy) { + startScroll(startX, startY, dx, dy, DEFAULT_DURATION); + } + + /** + * Start scrolling by providing a starting point and the distance to travel. + * + * @param startX Starting horizontal scroll offset in pixels. Positive + * numbers will scroll the content to the left. + * @param startY Starting vertical scroll offset in pixels. Positive numbers + * will scroll the content up. + * @param dx Horizontal distance to travel. Positive numbers will scroll the + * content to the left. + * @param dy Vertical distance to travel. Positive numbers will scroll the + * content up. + * @param duration Duration of the scroll in milliseconds. + */ + public void startScroll(int startX, int startY, int dx, int dy, int duration) { + mMode = SCROLL_MODE; + mFinished = false; + mDuration = duration; + mStartTime = AnimationUtils.currentAnimationTimeMillis(); + mStartX = startX; + mStartY = startY; + mFinalX = startX + dx; + mFinalY = startY + dy; + mDeltaX = dx; + mDeltaY = dy; + mDurationReciprocal = 1.0f / (float) mDuration; + } + + /** + * Start scrolling based on a fling gesture. The distance travelled will + * depend on the initial velocity of the fling. + * + * @param startX Starting point of the scroll (X) + * @param startY Starting point of the scroll (Y) + * @param velocityX Initial velocity of the fling (X) measured in pixels per + * second. + * @param velocityY Initial velocity of the fling (Y) measured in pixels per + * second + * @param minX Minimum X value. The scroller will not scroll past this + * point. + * @param maxX Maximum X value. The scroller will not scroll past this + * point. + * @param minY Minimum Y value. The scroller will not scroll past this + * point. + * @param maxY Maximum Y value. The scroller will not scroll past this + * point. + */ + public void fling(int startX, int startY, int velocityX, int velocityY, + int minX, int maxX, int minY, int maxY) { + // Continue a scroll or fling in progress + if (mFlywheel && !mFinished) { + float oldVel = getCurrVelocity(); + + float dx = (float) (mFinalX - mStartX); + float dy = (float) (mFinalY - mStartY); + float hyp = FloatMath.sqrt(dx * dx + dy * dy); + + float ndx = dx / hyp; + float ndy = dy / hyp; + + float oldVelocityX = ndx * oldVel; + float oldVelocityY = ndy * oldVel; + if (Math.signum(velocityX) == Math.signum(oldVelocityX) && + Math.signum(velocityY) == Math.signum(oldVelocityY)) { + velocityX += oldVelocityX; + velocityY += oldVelocityY; + } + } + + mMode = FLING_MODE; + mFinished = false; + + float velocity = FloatMath.sqrt(velocityX * velocityX + velocityY * velocityY); + + mVelocity = velocity; + float ALPHA = 800; + final double l = Math.log(START_TENSION * velocity / ALPHA); + mDuration = (int) (1000.0 * Math.exp(l / (DECELERATION_RATE - 1.0))); + mStartTime = AnimationUtils.currentAnimationTimeMillis(); + mStartX = startX; + mStartY = startY; + + float coeffX = velocity == 0 ? 1.0f : velocityX / velocity; + float coeffY = velocity == 0 ? 1.0f : velocityY / velocity; + + int totalDistance = + (int) (ALPHA * Math.exp(DECELERATION_RATE / (DECELERATION_RATE - 1.0) * l)); + + mMinX = minX; + mMaxX = maxX; + mMinY = minY; + mMaxY = maxY; + + mFinalX = startX + Math.round(totalDistance * coeffX); + // Pin to mMinX <= mFinalX <= mMaxX + mFinalX = Math.min(mFinalX, mMaxX); + mFinalX = Math.max(mFinalX, mMinX); + + mFinalY = startY + Math.round(totalDistance * coeffY); + // Pin to mMinY <= mFinalY <= mMaxY + mFinalY = Math.min(mFinalY, mMaxY); + mFinalY = Math.max(mFinalY, mMinY); + } + + static float viscousFluid(float x) + { + x *= sViscousFluidScale; + if (x < 1.0f) { + x -= (1.0f - (float)Math.exp(-x)); + } else { + float start = 0.36787944117f; // 1/e == exp(-1) + x = 1.0f - (float)Math.exp(1.0f - x); + x = start + x * (1.0f - start); + } + x *= sViscousFluidNormalize; + return x; + } + + /** + * Stops the animation. Contrary to {@link #forceFinished(boolean)}, + * aborting the animating cause the scroller to move to the final x and y + * position + * + * @see #forceFinished(boolean) + */ + public void abortAnimation() { + mCurrX = mFinalX; + mCurrY = mFinalY; + mFinished = true; + } + + /** + * Extend the scroll animation. This allows a running animation to scroll + * further and longer, when used with {@link #setFinalX(int)} or {@link #setFinalY(int)}. + * + * @param extend Additional time to scroll in milliseconds. + * @see #setFinalX(int) + * @see #setFinalY(int) + */ + public void extendDuration(int extend) { + int passed = timePassed(); + mDuration = passed + extend; + mDurationReciprocal = 1.0f / mDuration; + mFinished = false; + } + + /** + * Returns the time elapsed since the beginning of the scrolling. + * + * @return The elapsed time in milliseconds. + */ + public int timePassed() { + return (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime); + } + + /** + * Sets the final position (X) for this scroller. + * + * @param newX The new X offset as an absolute distance from the origin. + * @see #extendDuration(int) + * @see #setFinalY(int) + */ + public void setFinalX(int newX) { + mFinalX = newX; + mDeltaX = mFinalX - mStartX; + mFinished = false; + } + + /** + * Sets the final position (Y) for this scroller. + * + * @param newY The new Y offset as an absolute distance from the origin. + * @see #extendDuration(int) + * @see #setFinalX(int) + */ + public void setFinalY(int newY) { + mFinalY = newY; + mDeltaY = mFinalY - mStartY; + mFinished = false; + } + + public boolean isScrollingInDirection(float xvel, float yvel) { + return !mFinished && Math.signum(xvel) == Math.signum(mFinalX - mStartX) && + Math.signum(yvel) == Math.signum(mFinalY - mStartY); + } +} diff --git a/TMessagesProj/src/main/res/values-ar/strings.xml b/TMessagesProj/src/main/res/values-ar/strings.xml index 9e24a7e9..64851a0e 100644 --- a/TMessagesProj/src/main/res/values-ar/strings.xml +++ b/TMessagesProj/src/main/res/values-ar/strings.xml @@ -51,6 +51,7 @@ حذف وخروج الاسم مخفي اختر محادثة + إضغط بإستمرار على المستخدم العرض %1$s يستخدم إصدار قديم من تيليجرام، لذلك، الصور السرية ستظهر في وضع الموافقة.\n\nعندما يقوم %2$s بتحديث تيليجرام، الصور التي بها عداد دقيقة أو أقل ستعمل بطريقة \"الاستمرار بالضغط للإستعراض\"، وسيتم إخبارك عندما يلتقط المستقبل صورة من شاشته. قائمة الرسالة الجماعية @@ -201,6 +202,7 @@ غير معروف معلومات هاتف + اسم مستخدم معرّفك المعذرة، اسم المستخدم تم اختياره مسبقًا. @@ -211,8 +213,8 @@ يمكنك اختيار اسم مستخدم في ]]>تيليجرام]]>. إذا قمت بذلك، سيستطيع الناس إيجادك باستخدام الاسم المستخدم والتواصل معك من دون معرفة رقمك.
    ]]>يمكنك استخدام ]]>حروف اللغة الإنجليزية]]>, ]]>وأرقامها]]> و كذلك الخط. لا بد من استخدام ]]>٥]]> حروف على الأقل.
    جاري مراجعة اسم المستخدم... %1$s متاح. - None - An error occurred + لا يوجد + حدث خطأ. تم تعيين كافة الإشعارات افتراضيا حجم نص الرسائل @@ -384,6 +386,7 @@ أعد الإرسال باستخدام اسمي هل ترغب في إرسال رسالة إلى %1$s؟ ؟%1$s هل تريد إعادة توجيه الرسائل إلى + .Sorry, this feature is currently not available in your country تيليجرام سريع diff --git a/TMessagesProj/src/main/res/values-de/strings.xml b/TMessagesProj/src/main/res/values-de/strings.xml index 3fe8b822..9d888804 100644 --- a/TMessagesProj/src/main/res/values-de/strings.xml +++ b/TMessagesProj/src/main/res/values-de/strings.xml @@ -51,6 +51,7 @@ Löschen und beenden Versteckter Name Chat auswählen + Tippen und Halten %1$s benutzt eine ältere Version von Telegram, sodass Fotos in Geheimen Chats im Kompatibilitätsmodus angezeigt werden.\n\nSobald %2$s Telegram aktualisiert, werden Fotos mit Timern von 1 Minute und kürzer per \"Tippen und Halten\" angezeigt. Du wirst benachrichtigt, sobald dein Chatpartner ein Bildschirmfoto macht. Broadcast Liste @@ -201,6 +202,7 @@ Unbekannt INFO Telefon + Benutzername Dein Benutzername Leider ist dieser Benutzername vergeben. @@ -208,11 +210,11 @@ Ein Benutzername benötigt mindestens 5 Zeichen. Ein Benutzername darf maximal 32 Zeichen haben. Benutzernamen dürfen leider nicht mit einer Zahl anfangen. - Wähle einen Benutzernamen, wenn du von anderen bei]]>Telegram]]>gefunden werden willst – ohne, dass sie deine Nummer kennen müssen.
    ]]>Erlaubt sind ]]>a–z]]>, ]]>0–9]]> und Unterstriche. Die Mindestlänge beträgt ]]>5]]> Zeichen.
    + Wähle einen Benutzernamen, wenn du von anderen bei]]>Telegram]]>gefunden werden willst — ohne, dass sie deine Nummer kennen müssen.
    ]]>Erlaubt sind ]]>a-z]]>, ]]>0-9]]> und Unterstriche. Die Mindestlänge beträgt ]]>5]]> Zeichen.
    Prüfe Benutzername... %1$s ist verfügbar. - None - An error occurred + Keiner + Es ist ein Fehler aufgetreten. Alle Einstellungen für Mitteilungen zurücksetzen Textgröße für Nachrichten @@ -384,6 +386,7 @@ mit meinem Namen weiterleiten Nachricht an %1$s senden? Weiterleiten an %1$s? + Sorry, this feature is currently not available in your country. Telegram Schnell diff --git a/TMessagesProj/src/main/res/values-es/strings.xml b/TMessagesProj/src/main/res/values-es/strings.xml index 2eecba92..ce8ca4e7 100644 --- a/TMessagesProj/src/main/res/values-es/strings.xml +++ b/TMessagesProj/src/main/res/values-es/strings.xml @@ -22,10 +22,10 @@ ¿No recibiste el código? Tu nombre - Ingresa tu nombre y apellido + Ingresa tu nombre y apellidos Nombre (requerido) - Apellido (opcional) + Apellidos (opcional) Cancelar registro Chats @@ -51,6 +51,7 @@ Eliminar y salir Nombre oculto Elige el chat + Mantén pulsado para ver %1$s usa una versión antigua de Telegram, así que las fotos secretas serán mostradas en un modo de compatibilidad.\n\nCuando %2$s actualice Telegram, las fotos con autodestrucción de 1 minuto o menos funcionarán con el modo \'Mantén pulsado para ver\', y te notificaremos siempre que la otra parte haga una captura de pantalla. Lista de difusión @@ -201,6 +202,7 @@ Desconocido INFORMACIÓN Teléfono + Apodo Tu apodo Lo siento, este apodo ya está ocupado. @@ -211,8 +213,8 @@ Puedes elegir un apodo en ]]>Telegram]]>. Si lo haces, otras personas te podrán encontrar por ese apodo y contactarte sin saber tu número de teléfono.
    ]]>Puedes usar ]]>a–z]]>, ]]>0–9]]> y guiones bajos. La longitud mínima es de ]]>5]]> caracteres.
    Verificando apodo... %1$s está disponible. - None - An error occurred + Ninguno + Ocurrió un error. Restablecer las notificaciones Tamaño del texto @@ -238,7 +240,7 @@ Usuarios bloqueados Guardar fotos entrantes Cerrar sesión - TU NOMBRE Y APELLIDO + TU NOMBRE Y APELLIDOS Sin sonido Por defecto SOPORTE @@ -264,7 +266,7 @@ Importar contactos Sólo vía Wi-Fi Nombre - Apellido + Apellidos Color del LED Notificaciones emergentes Desactivadas @@ -360,7 +362,7 @@ Muchos intentos. Por favor, inténtalo más tarde. Código inválido Nombre inválido - Apellido inválido + Apellidos inválidos Cargando... No tienes reproductor de vídeo. Por favor, instala uno para continuar. Por favor, envíanos un correo electrónico a sms@telegram.org y cuéntanos tu problema. @@ -384,6 +386,7 @@ reenviar desde mi nombre ¿Enviar mensajes a %1$s? ¿Reenviar mensajes a %1$s? + Sorry, this feature is currently not available in your country. Telegram Rápida diff --git a/TMessagesProj/src/main/res/values-it/strings.xml b/TMessagesProj/src/main/res/values-it/strings.xml index 0b37c268..83596258 100644 --- a/TMessagesProj/src/main/res/values-it/strings.xml +++ b/TMessagesProj/src/main/res/values-it/strings.xml @@ -51,6 +51,7 @@ Elimina ed esci Nome nascosto Seleziona chat + Tieni premuto per vedere %1$s sta usando una versione vecchia di Telegram, quindi le foto segrete verranno visualizzate in modalità di compatibilità.\n\nUna volta che %2$s avrà aggiornato Telegram, le foto con il timer minore di 1 minuto funzioneranno in modalità \'Tieni premuto per vedere\' , e verrai notificato ogni volta che l\'altro esegue uno screenshot. Lista broadcast @@ -201,6 +202,7 @@ Sconosciuto INFO Telefono + Nome utente Il tuo Nome Utente Nome utente già preso. @@ -211,8 +213,8 @@ Puoi scegliere un nome utente su ]]>Telegram]]>. Se lo fai, le altre persone potranno trovarti tramite questo nome utente e contattarti senza conoscere il tuo numero di telefono.
    ]]>Puoi usare ]]>a–z]]>, ]]>0–9]]> e underscore. La lunghezza minima è di ]]>5]]> caratteri.
    Controllando il nome utente... %1$s è disponibile. - None - An error occurred + Nessuno + Si è verificato un errore. Ripristina tutte le impostazioni di notifica predefinite Dimensione testo messaggi @@ -384,6 +386,7 @@ inoltra dal mio nome Inviare messaggi a %1$s? Inoltra messaggi a %1$s? + Ci spiace, questa funzione non è disponibile nel tuo paese. Telegram Veloce diff --git a/TMessagesProj/src/main/res/values-ko/strings.xml b/TMessagesProj/src/main/res/values-ko/strings.xml index 3aa93ccc..c6314c7f 100644 --- a/TMessagesProj/src/main/res/values-ko/strings.xml +++ b/TMessagesProj/src/main/res/values-ko/strings.xml @@ -38,7 +38,7 @@ 결과 없음 채팅방이 없습니다... 대화를 시작하려면 우측 상단의\n초대하기 버튼을 누르거나\n메뉴 버튼을 눌러 보세요. - 네트워크 연결을 기다리는 중... + 대기 중... 연결 중... 업데이트 중... 비밀대화 시작 @@ -51,6 +51,8 @@ 채팅방 나가기 숨긴 이름 채팅방 선택 + 꾹 눌러서 보기 + %1$s님의 텔레그램 버전이 낮아 비밀 사진을 호환성 모드로 표시합니다.\n\n%2$s님이 텔레그램을 업데이트하고 나면, 자동삭제 시간이 1분 이하인 사진은 \"탭하고 누르고 있어야 보임\" 상태가 되며, 상대방이 화면을 캡처할 때 마다 알림을 받습니다. 단체 메시지 리스트 새 단체 메시지 리스트 @@ -160,7 +162,7 @@ 마지막 접속: 마지막 접속: 친구 초대 - GLOBAL SEARCH + 전체 검색 메시지 보내기... 그룹 이름 입력 @@ -197,21 +199,22 @@ 자동삭제 타이머 해제 이 이미지는 ]]>%1$s]]>님과의 비밀대화에 사용 중인 암호화 키의 모습입니다.
    ]]>이 이미지가 ]]>%2$s]]>님의 암호화 키와 똑같다면 대화는 200%% 안전합니다.
    ]]>더 자세한 사항은 telegram.org 를 참고해 주세요.
    - Unknown - INFO + 알 수 없음 + 정보 전화번호 - Username - Your Username - Sorry, this username is already taken. - Sorry, this username is invalid. - A username must have at least 5 characters. - A username must have maximum 32 characters. - Sorry, a username can\'t start with a number. - You can choose a username on ]]>Telegram]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.
    ]]>You can use ]]>a–z]]>, ]]>0–9]]> and underscores. Minimum length is ]]>5]]> characters.
    - Checking username... - %1$s is available. - None - An error occurred + + 아이디 + 아이디 + 이미 사용 중인 아이디입니다. + 올바른 아이디를 입력하세요. + 아이디는 최소 다섯 글자 이상 입력해야 합니다. + 아이디는 최대 32자까지만 가능합니다. + 아이디는 숫자로 시작할 수 없습니다. + 텔레그램 아이디를 설정할 수 있습니다. 아이디를 설정하면 회원님의 전화번호를 몰라도 아이디로 회원님을 찾아 대화를 나눌 수 있습니다.
    ]]>아이디는 영문, 밑줄, 숫자로 (]]>a~z]]>, ]]>_]]>, ]]>0~9]]>) ]]>다섯 글자]]> 이상으로 설정해 주세요.
    + 아이디 확인 중... + %1$s: 사용 가능합니다. + 없음 + 오류가 발생했습니다. 모든 알림 설정이 초기화되었습니다 채팅 글자 크기 @@ -383,6 +386,7 @@ 내 이름으로 전달 %1$s 그룹에 메시지를 보낼까요? %1$s 그룹에 메시지를 전달할까요? + 이 기능은 회원님의 국가에서는 사용할 수 없습니다. 텔레그램 눈부신 속도 @@ -436,36 +440,36 @@ 채팅방 %1$d개에서 채팅방 %1$d개에서 채팅방 %1$d개에서 - %1$d seconds - %1$d second - %1$d seconds - %1$d seconds - %1$d seconds - %1$d seconds - %1$d minutes - %1$d minute - %1$d minutes - %1$d minutes - %1$d minutes - %1$d minutes - %1$d hours - %1$d hour - %1$d hours - %1$d hours - %1$d hours - %1$d hours - %1$d days - %1$d day - %1$d days - %1$d days - %1$d days - %1$d days - %1$d weeks - %1$d week - %1$d weeks - %1$d weeks - %1$d weeks - %1$d weeks + %1$d초 + %1$d초 + %1$d초 + %1$d초 + %1$d초 + %1$d초 + %1$d분 + %1$d분 + %1$d분 + %1$d분 + %1$d분 + %1$d분 + %1$d시간 + %1$d시간 + %1$d시간 + %1$d시간 + %1$d시간 + %1$d시간 + %1$d일 + %1$d일 + %1$d일 + %1$d일 + %1$d일 + %1$d일 + %1$d주 + %1$d주 + %1$d주 + %1$d주 + %1$d주 + %1$d주 M\'월\' d\'일\' yyyy.MM.dd. diff --git a/TMessagesProj/src/main/res/values-nl/strings.xml b/TMessagesProj/src/main/res/values-nl/strings.xml index 7916a2fb..eafe2848 100644 --- a/TMessagesProj/src/main/res/values-nl/strings.xml +++ b/TMessagesProj/src/main/res/values-nl/strings.xml @@ -51,7 +51,8 @@ Verwijderen en verlaten Verborgen naam Kies een gesprek - %1$s gebruikt een oudere versie van Telegram, dus worden geheime foto\'s weergegeven in de compatibiliteitsmodus.\n\nZodra %2$s Telegram update werken foto\'s met timers voor 1 minuut of minder in de \'Houd ingedrukt om te bekijken\'-modus en krijg je een bericht wanneer de andere partij een schermafbeelding maakt. + Druk en houd ingedrukt + %1$s gebruikt een oudere versie van Telegram, dus worden geheime foto\'s weergegeven in de compatibiliteitsmodus.\n\nZodra %2$s Telegram updatet werken foto\'s met timers voor 1 minuut of minder in de \'Druk en houd ingedrukt\'-modus en krijg je een bericht wanneer de andere partij een schermafbeelding maakt. Verzendlijst Nieuwe verzendlijst @@ -201,6 +202,7 @@ Onbekend INFORMATIE Telefoon + Gebruikersnaam Kies een naam Sorry, deze gebruikersnaam is al bezet. @@ -211,8 +213,8 @@ Je kan een gebruikersnaam kiezen voor ]]>Telegram]]>. Hiermee kunnen anderen je vinden en contact met je opnemen zonder je telefoonnummer te weten.
    ]]>Je mag ]]>a–z]]>, ]]>0–9]]> en liggend streepje gebruiken. De minimale lengte is ]]>5]]> tekens.
    Gebruikersnaam controleren. %1$s is beschikbaar. - None - An error occurred + Geen + Er is een fout opgetreden. Alle meldingsinstellingen herstellen Tekstgrootte berichten @@ -384,6 +386,7 @@ doorsturen via mijn eigen naam Berichten naar %1$s verzenden? Berichten naar %1$s doorsturen? + Sorry, deze functie is momenteel niet beschikbaar in jouw land. Telegram Snel diff --git a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml index a6270eed..df6d5c48 100644 --- a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml @@ -51,6 +51,7 @@ Apagar e sair Nome oculto Selecione uma Conversa + Toque e segure para ver %1$s está usando uma versão mais antiga do Telegram, por isso fotos secretas serão mostradas em modo de compatibilidade.\n\nAssim que %2$s atualize o Telegram, fotos com timers de 1 minuto ou menos passarão a funcionar no modo ‘Toque e segure para ver’, e você será notificado caso a outra pessoa salve a tela. Lista de Broadcast @@ -201,6 +202,7 @@ Desconhecido INFO Telefone + Nome de Usuário Seu nome de usuário Desculpe, este usuário já existe. @@ -211,8 +213,8 @@ Você pode escolher um nome de usuário no ]]>Telegram]]>. Assim, outras pessoas poderão te encontrar pelo nome de usuário e entrar em contato sem precisar saber seu telefone.
    ]]>Você pode usar ]]>a–z]]>, ]]>0–9]]> e underline. O tamanho mínimo é ]]>5]]> caracteres.
    Verificando nome de usuário... %1$s está disponível. - None - An error occurred + Nenhum + Ocorreu um erro. Restaurar todas as configurações de notificação Tamanho do texto nas mensagens @@ -384,6 +386,7 @@ encaminhar pelo meu nome Enviar mensagens para %1$s? Encaminhar mensagem para %1$s? + Sorry, this feature is currently not available in your country. Telegram Rápido diff --git a/TMessagesProj/src/main/res/values-pt-rPT/strings.xml b/TMessagesProj/src/main/res/values-pt-rPT/strings.xml index b11dad27..f79e0ff2 100644 --- a/TMessagesProj/src/main/res/values-pt-rPT/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rPT/strings.xml @@ -51,6 +51,7 @@ Apagar e sair Nome oculto Selecione uma Conversa + Toque e segure para ver %1$s está usando uma versão mais antiga do Telegram, por isso fotos secretas serão mostradas em modo de compatibilidade.\n\nAssim que %2$s atualize o Telegram, fotos com timers de 1 minuto ou menos passarão a funcionar no modo ‘Toque e segure para ver’, e você será notificado caso a outra pessoa salve a tela. Lista de Broadcast @@ -201,6 +202,7 @@ Desconhecido INFO Telefone + Nome de Usuário Seu nome de usuário Desculpe, este usuário já existe. @@ -211,8 +213,8 @@ Você pode escolher um nome de usuário no ]]>Telegram]]>. Assim, outras pessoas poderão te encontrar pelo nome de usuário e entrar em contato sem precisar saber seu telefone.
    ]]>Você pode usar ]]>a–z]]>, ]]>0–9]]> e underline. O tamanho mínimo é ]]>5]]> caracteres.
    Verificando nome de usuário... %1$s está disponível. - None - An error occurred + Nenhum + Ocorreu um erro. Restaurar todas as configurações de notificação Tamanho do texto nas mensagens @@ -384,6 +386,7 @@ encaminhar pelo meu nome Enviar mensagens para %1$s? Encaminhar mensagem para %1$s? + Sorry, this feature is currently not available in your country. Telegram Rápido From d03fa95568bfcb5bb98ae6c79fedc037eaf0903a Mon Sep 17 00:00:00 2001 From: DrKLO Date: Thu, 23 Oct 2014 11:55:32 +0400 Subject: [PATCH 17/18] Bug fixes --- TMessagesProj/build.gradle | 4 +- .../Adapters/BaseContactsSearchAdapter.java | 4 +- .../ContactsActivitySearchAdapter.java | 43 ++++++++++++------- .../org/telegram/ui/ChatProfileActivity.java | 1 + .../org/telegram/ui/ContactsActivity.java | 12 +++--- .../java/org/telegram/ui/LaunchActivity.java | 3 ++ .../org/telegram/ui/MessagesActivity.java | 37 +++++++++------- .../org/telegram/ui/PhotoPickerActivity.java | 3 ++ .../ui/SettingsChangeUsernameActivity.java | 2 +- 9 files changed, 67 insertions(+), 42 deletions(-) diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index d0dbed6a..56b60108 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -80,7 +80,7 @@ android { defaultConfig { minSdkVersion 8 targetSdkVersion 19 - versionCode 371 - versionName "1.9.5" + versionCode 372 + versionName "1.9.6" } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseContactsSearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseContactsSearchAdapter.java index bc0b4f9e..e639fb16 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseContactsSearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseContactsSearchAdapter.java @@ -18,7 +18,7 @@ import java.util.ArrayList; public class BaseContactsSearchAdapter extends BaseFragmentAdapter { - protected ArrayList globalSearch; + protected ArrayList globalSearch = new ArrayList(); private long reqId = 0; private int lastReqId; protected String lastFoundUsername = null; @@ -29,7 +29,7 @@ public class BaseContactsSearchAdapter extends BaseFragmentAdapter { ConnectionsManager.getInstance().cancelRpc(reqId, true); reqId = 0; } - globalSearch = null; + globalSearch.clear(); lastReqId = 0; notifyDataSetChanged(); return; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivitySearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivitySearchAdapter.java index b1a1f02a..cab7b647 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivitySearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivitySearchAdapter.java @@ -36,17 +36,21 @@ public class ContactsActivitySearchAdapter extends BaseContactsSearchAdapter { private ArrayList searchResult; private ArrayList searchResultNames; private Timer searchTimer; + private boolean allowUsernameSearch; - public ContactsActivitySearchAdapter(Context context, HashMap arg1) { + public ContactsActivitySearchAdapter(Context context, HashMap arg1, boolean usernameSearch) { mContext = context; ignoreUsers = arg1; + allowUsernameSearch = usernameSearch; } public void searchDialogs(final String query) { if (query == null) { - searchResult = null; - searchResultNames = null; - queryServerSearch(null); + searchResult.clear(); + searchResultNames.clear(); + if (allowUsernameSearch) { + queryServerSearch(null); + } notifyDataSetChanged(); } else { try { @@ -76,7 +80,9 @@ public class ContactsActivitySearchAdapter extends BaseContactsSearchAdapter { AndroidUtilities.RunOnUIThread(new Runnable() { @Override public void run() { - queryServerSearch(query); + if (allowUsernameSearch) { + queryServerSearch(query); + } final ArrayList contactsCopy = new ArrayList(); contactsCopy.addAll(ContactsController.getInstance().contacts); Utilities.searchQueue.postRunnable(new Runnable() { @@ -128,13 +134,13 @@ public class ContactsActivitySearchAdapter extends BaseContactsSearchAdapter { @Override public boolean isEnabled(int i) { - return i != (searchResult == null ? 0 : searchResult.size()); + return i != searchResult.size(); } @Override public int getCount() { - int count = searchResult == null ? 0 : searchResult.size(); - int globalCount = globalSearch == null ? 0 : globalSearch.size(); + int count = searchResult.size(); + int globalCount = globalSearch.size(); if (globalCount != 0) { count += globalCount + 1; } @@ -142,8 +148,8 @@ public class ContactsActivitySearchAdapter extends BaseContactsSearchAdapter { } public boolean isGlobalSearch(int i) { - int localCount = searchResult == null ? 0 : searchResult.size(); - int globalCount = globalSearch == null ? 0 : globalSearch.size(); + int localCount = searchResult.size(); + int globalCount = globalSearch.size(); if (i >= 0 && i < localCount) { return false; } else if (i > localCount && i <= globalCount + localCount) { @@ -154,8 +160,8 @@ public class ContactsActivitySearchAdapter extends BaseContactsSearchAdapter { @Override public TLRPC.User getItem(int i) { - int localCount = searchResult == null ? 0 : searchResult.size(); - int globalCount = globalSearch == null ? 0 : globalSearch.size(); + int localCount = searchResult.size(); + int globalCount = globalSearch.size(); if (i >= 0 && i < localCount) { return searchResult.get(i); } else if (i > localCount && i <= globalCount + localCount) { @@ -176,7 +182,7 @@ public class ContactsActivitySearchAdapter extends BaseContactsSearchAdapter { @Override public View getView(int i, View view, ViewGroup viewGroup) { - if (i == (searchResult == null ? 0 : searchResult.size())) { + if (i == searchResult.size()) { if (view == null) { view = new SettingsSectionLayout(mContext); ((SettingsSectionLayout) view).setText(LocaleController.getString("GlobalSearch", R.string.GlobalSearch)); @@ -192,7 +198,12 @@ public class ContactsActivitySearchAdapter extends BaseContactsSearchAdapter { if (user != null) { CharSequence username = null; if (i > searchResult.size() && user.username != null) { - username = Html.fromHtml(String.format("@%s%s", user.username.substring(0, lastFoundUsername.length()), user.username.substring(lastFoundUsername.length()))); + try { + username = Html.fromHtml(String.format("@%s%s", user.username.substring(0, lastFoundUsername.length()), user.username.substring(lastFoundUsername.length()))); + } catch (Exception e) { + username = user.username; + FileLog.e("tmessages", e); + } } ((ChatOrUserCell) view).setData(user, null, null, i < searchResult.size() ? searchResultNames.get(i) : null, username); @@ -211,7 +222,7 @@ public class ContactsActivitySearchAdapter extends BaseContactsSearchAdapter { @Override public int getItemViewType(int i) { - if (i == (searchResult == null ? 0 : searchResult.size())) { + if (i == searchResult.size()) { return 1; } return 0; @@ -224,6 +235,6 @@ public class ContactsActivitySearchAdapter extends BaseContactsSearchAdapter { @Override public boolean isEmpty() { - return (searchResult == null || searchResult.size() == 0) && (globalSearch == null || globalSearch.isEmpty()); + return searchResult.isEmpty() && globalSearch.isEmpty(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileActivity.java index 8c56eca9..dc7dd128 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileActivity.java @@ -477,6 +477,7 @@ public class ChatProfileActivity extends BaseFragment implements NotificationCen args.putBoolean("destroyAfterSelect", true); args.putBoolean("usersAsSections", true); args.putBoolean("returnAsResult", true); + args.putBoolean("allowUsernameSearch", false); if (chat_id > 0) { args.putString("selectAlertString", LocaleController.getString("AddToTheGroup", R.string.AddToTheGroup)); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java index 9bfd611b..a65ce45d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java @@ -73,6 +73,7 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter private String inviteText; private boolean updatingInviteText = false; + private boolean allowUsernameSearch = true; private ContactsActivityDelegate delegate; public static interface ContactsActivityDelegate { @@ -92,11 +93,12 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter NotificationCenter.getInstance().addObserver(this, NotificationCenter.encryptedChatCreated); if (arguments != null) { onlyUsers = getArguments().getBoolean("onlyUsers", false); - destroyAfterSelect = getArguments().getBoolean("destroyAfterSelect", false); - usersAsSections = getArguments().getBoolean("usersAsSections", false); - returnAsResult = getArguments().getBoolean("returnAsResult", false); - createSecretChat = getArguments().getBoolean("createSecretChat", false); + destroyAfterSelect = arguments.getBoolean("destroyAfterSelect", false); + usersAsSections = arguments.getBoolean("usersAsSections", false); + returnAsResult = arguments.getBoolean("returnAsResult", false); + createSecretChat = arguments.getBoolean("createSecretChat", false); selectAlertString = arguments.getString("selectAlertString"); + allowUsernameSearch = arguments.getBoolean("allowUsernameSearch", true); } SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); @@ -200,7 +202,7 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter emptyTextView = (TextView)fragmentView.findViewById(R.id.searchEmptyView); emptyTextView.setText(LocaleController.getString("NoContacts", R.string.NoContacts)); - searchListViewAdapter = new ContactsActivitySearchAdapter(getParentActivity(), ignoreUsers); + searchListViewAdapter = new ContactsActivitySearchAdapter(getParentActivity(), ignoreUsers, allowUsernameSearch); listView = (PinnedHeaderListView)fragmentView.findViewById(R.id.listView); listView.setEmptyView(emptyTextView); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index 9cc07547..9806c5d8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -787,6 +787,9 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa public void fixLayout() { if (AndroidUtilities.isTablet()) { + if (actionBarLayout == null) { + return; + } actionBarLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MessagesActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/MessagesActivity.java index c65d8152..6f2b8ec6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/MessagesActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/MessagesActivity.java @@ -619,8 +619,8 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter private Context mContext; private Timer searchTimer; - private ArrayList searchResult; - private ArrayList searchResultNames; + private ArrayList searchResult = new ArrayList(); + private ArrayList searchResultNames = new ArrayList(); public MessagesAdapter(Context context) { mContext = context; @@ -656,8 +656,8 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter public boolean isGlobalSearch(int i) { if (searching && searchWas) { - int localCount = searchResult == null ? 0 : searchResult.size(); - int globalCount = globalSearch == null ? 0 : globalSearch.size(); + int localCount = searchResult.size(); + int globalCount = globalSearch.size(); if (i >= 0 && i < localCount) { return false; } else if (i > localCount && i <= globalCount + localCount) { @@ -669,8 +669,8 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter public void searchDialogs(final String query) { if (query == null) { - searchResult = null; - searchResultNames = null; + searchResult.clear(); + searchResultNames.clear(); queryServerSearch(null); notifyDataSetChanged(); } else { @@ -710,14 +710,14 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter @Override public boolean isEnabled(int i) { - return !(searching && searchWas) || i != (searchResult == null ? 0 : searchResult.size()); + return !(searching && searchWas) || i != searchResult.size(); } @Override public int getCount() { if (searching && searchWas) { - int count = searchResult == null ? 0 : searchResult.size(); - int globalCount = globalSearch == null ? 0 : globalSearch.size(); + int count = searchResult.size(); + int globalCount = globalSearch.size(); if (globalCount != 0) { count += globalCount + 1; } @@ -741,8 +741,8 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter @Override public TLObject getItem(int i) { if (searching && searchWas) { - int localCount = searchResult == null ? 0 : searchResult.size(); - int globalCount = globalSearch == null ? 0 : globalSearch.size(); + int localCount = searchResult.size(); + int globalCount = globalSearch.size(); if (i >= 0 && i < localCount) { return searchResult.get(i); } else if (i > localCount && i <= globalCount + localCount) { @@ -776,7 +776,7 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter @Override public View getView(int i, View view, ViewGroup viewGroup) { if (searching && searchWas) { - if (i == (searchResult == null ? 0 : searchResult.size())) { + if (i == searchResult.size()) { if (view == null) { view = new SettingsSectionLayout(mContext); ((SettingsSectionLayout) view).setText(LocaleController.getString("GlobalSearch", R.string.GlobalSearch)); @@ -805,8 +805,13 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter } CharSequence username = null; - if (i > searchResult.size() && user.username != null) { - username = Html.fromHtml(String.format("@%s%s", user.username.substring(0, lastFoundUsername.length()), user.username.substring(lastFoundUsername.length()))); + if (i > searchResult.size() && user != null && user.username != null) { + try { + username = Html.fromHtml(String.format("@%s%s", user.username.substring(0, lastFoundUsername.length()), user.username.substring(lastFoundUsername.length()))); + } catch (Exception e) { + username = user.username; + FileLog.e("tmessages", e); + } } ((ChatOrUserCell) view).setData(user, chat, encryptedChat, i < searchResult.size() ? searchResultNames.get(i) : null, username); @@ -847,7 +852,7 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter @Override public int getItemViewType(int i) { if (searching && searchWas) { - if (i == (searchResult == null ? 0 : searchResult.size())) { + if (i == searchResult.size()) { return 3; } return 2; @@ -866,7 +871,7 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter @Override public boolean isEmpty() { if (searching && searchWas) { - return (searchResult == null || searchResult.size() == 0) && (globalSearch == null || globalSearch.isEmpty()); + return searchResult.size() == 0 && globalSearch.isEmpty(); } if (MessagesController.getInstance().loadingDialogs && MessagesController.getInstance().dialogs.isEmpty()) { return false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerActivity.java index 351d86b3..8b93ea57 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerActivity.java @@ -279,6 +279,9 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen int count = listView.getChildCount(); for (int a = 0; a < count; a++) { View view = listView.getChildAt(a); + if (view.getTag() == null) { + continue; + } int num = (Integer)view.getTag(); if (num < 0 || num >= selectedAlbum.photos.size()) { continue; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java index 9a417704..d5fdfb34 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java @@ -239,7 +239,7 @@ public class SettingsChangeUsernameActivity extends BaseFragment { } return false; } - if (!(ch >= '0' && ch <= '9' || ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || a == '_')) { + if (!(ch >= '0' && ch <= '9' || ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch == '_')) { if (alert) { showErrorAlert(LocaleController.getString("UsernameInvalid", R.string.UsernameInvalid)); } else { From abf8f6f6199dfcc0df3cc315ce5ba1e4edeb9991 Mon Sep 17 00:00:00 2001 From: DrKLO Date: Thu, 23 Oct 2014 19:30:35 +0400 Subject: [PATCH 18/18] Bug fixes --- README.md | 21 +- TMessagesProj/build.gradle | 4 +- .../telegram/android/AndroidUtilities.java | 2 +- .../telegram/android/MessagesController.java | 8 +- .../org/telegram/android/MessagesStorage.java | 780 ++++++------------ .../telegram/android/SendMessagesHelper.java | 10 +- .../ContactsActivitySearchAdapter.java | 32 +- .../java/org/telegram/ui/ChatActivity.java | 2 +- .../org/telegram/ui/ChatProfileActivity.java | 2 +- .../telegram/ui/GroupCreateFinalActivity.java | 5 +- .../org/telegram/ui/MessagesActivity.java | 80 +- .../java/org/telegram/ui/PhotoViewer.java | 2 + .../ui/SettingsChangeUsernameActivity.java | 3 + .../org/telegram/ui/VideoEditorActivity.java | 12 +- .../ui/Views/ChatActivityEnterView.java | 26 +- TMessagesProj/src/main/res/anim/scale_in.xml | 4 +- TMessagesProj/src/main/res/anim/scale_out.xml | 4 +- 17 files changed, 368 insertions(+), 629 deletions(-) diff --git a/README.md b/README.md index d4affdf2..7b569217 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,30 @@ ## Telegram messenger for Android [Telegram](http://telegram.org) is a messaging app with a focus on speed and security. It’s superfast, simple and free. +This repo contains the official source code for [Telegram App for Android](https://play.google.com/store/apps/details?id=org.telegram.messenger). -This repo contains official [Telegram App for Android](https://play.google.com/store/apps/details?id=org.telegram.messenger) source code. +##Creating your Telegram Application + +We welcome all developers to use our API and source code to create applications on our platform. +There are several things we require from **all developers** for the moment. + +1. [**Obtain your own api_id**](https://core.telegram.org/api/obtaining_api_id) for your application. +2. Please **do not** use the name Telegram for your app — or make sure your users understand that it is unofficial. +3. Kindly **do not** use our standard logo (white paper plane in a blue circle) as your app's logo. +3. Please study our [**security guidelines**](https://core.telegram.org/mtproto/security_guidelines) and take good care of your users' data and privacy. +4. Please remember to publish **your** code too in order to comply with the licences. ### API, Protocol documentation -Documentation for Telegram API is available here: http://core.telegram.org/api +Telegram API manuals: http://core.telegram.org/api -Documentation for MTproto protocol is available here: http://core.telegram.org/mtproto +MTproto protocol manuals: http://core.telegram.org/mtproto ### Usage -**Beware of using dev branch and uploading it to any markets, in most cases it will work as you expecting** - -First of all your should take a look to **src/main/java/org/telegram/messenger/BuildVars.java** and fill it with correct values. +**Beware of using the dev branch and uploading it to any markets, in many cases it not will work as expected**. +First of all, take a look at **src/main/java/org/telegram/messenger/BuildVars.java** and fill it with correct values. Import the root folder into your IDE (tested on Android Studio), then run project. ### Localization diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index 56b60108..13c41af8 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -25,7 +25,7 @@ dependencies { android { compileSdkVersion 21 - buildToolsVersion '21.0.1' + buildToolsVersion '21.0.2' signingConfigs { debug { @@ -80,7 +80,7 @@ android { defaultConfig { minSdkVersion 8 targetSdkVersion 19 - versionCode 372 + versionCode 374 versionName "1.9.6" } } diff --git a/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java index ed9a09e9..3b346fd0 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java @@ -218,7 +218,7 @@ public class AndroidUtilities { } public static File getCacheDir() { - if (Environment.getExternalStorageState().startsWith(Environment.MEDIA_MOUNTED)) { + if (Environment.getExternalStorageState() == null || Environment.getExternalStorageState().startsWith(Environment.MEDIA_MOUNTED)) { try { File file = ApplicationLoader.applicationContext.getExternalCacheDir(); if (file != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java index eb95c9a5..80838222 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java @@ -1711,7 +1711,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } public void markMessageAsRead(final long dialog_id, final long random_id, int ttl) { - if (random_id == 0 || dialog_id == 0) { + if (random_id == 0 || dialog_id == 0 || ttl <= 0) { return; } int lower_part = (int)dialog_id; @@ -1726,10 +1726,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter ArrayList random_ids = new ArrayList(); random_ids.add(random_id); SendMessagesHelper.getInstance().sendMessagesReadMessage(chat, random_ids, null); - if (ttl > 0) { - int time = ConnectionsManager.getInstance().getCurrentTime(); - MessagesStorage.getInstance().createTaskForSecretChat(chat.id, time, time, 0, random_ids); - } + int time = ConnectionsManager.getInstance().getCurrentTime(); + MessagesStorage.getInstance().createTaskForSecretChat(chat.id, time, time, 0, random_ids); } public void markDialogAsRead(final long dialog_id, final int max_id, final int max_positive_id, final int offset, final int max_date, final boolean was, final boolean popup) { diff --git a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java index 479401bf..4b8598b7 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java @@ -499,58 +499,15 @@ public class MessagesStorage { cursor.dispose(); if (!encryptedChatIds.isEmpty()) { - String stringToLoad = TextUtils.join(",", encryptedChatIds); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer, seq_in, seq_out FROM enc_chats WHERE uid IN(%s)", stringToLoad)); - while (cursor.next()) { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - encryptedChats.add(chat); - chat.user_id = cursor.intValue(1); - if (!userIds.contains(chat.user_id)) { - userIds.add(chat.user_id); - } - chat.a_or_b = cursor.byteArrayValue(2); - chat.auth_key = cursor.byteArrayValue(3); - chat.ttl = cursor.intValue(4); - chat.layer = cursor.intValue(5); - chat.seq_in = cursor.intValue(6); - chat.seq_out = cursor.intValue(7); - } - buffersStorage.reuseFreeBuffer(data); - } - cursor.dispose(); + getEncryptedChatsInternal(TextUtils.join(",", encryptedChatIds), encryptedChats, userIds); } if (!userIds.isEmpty()) { - String stringToLoad = TextUtils.join(",", userIds); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", stringToLoad)); - while (cursor.next()) { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - TLRPC.User user = (TLRPC.User) TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - if (user.status != null) { - user.status.expires = cursor.intValue(1); - } - users.add(user); - } - buffersStorage.reuseFreeBuffer(data); - } - cursor.dispose(); + getUsersInternal(TextUtils.join(",", userIds), users); } if (!chatIds.isEmpty()) { - String stringToLoad = TextUtils.join(",", chatIds); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid IN(%s)", stringToLoad)); - while (cursor.next()) { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - TLRPC.Chat chat = (TLRPC.Chat) TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - chats.add(chat); - } - buffersStorage.reuseFreeBuffer(data); - } - cursor.dispose(); + getChatsInternal(TextUtils.join(",", chatIds), chats); } } Collections.reverse(messages); @@ -639,19 +596,7 @@ public class MessagesStorage { cursor.dispose(); if (usersToLoad.length() != 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad.toString())); - while (cursor.next()) { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - users.add(user); - if (user.status != null) { - user.status.expires = cursor.intValue(1); - } - } - buffersStorage.reuseFreeBuffer(data); - } - cursor.dispose(); + getUsersInternal(usersToLoad.toString(), users); } MessagesController.getInstance().processLoadedBlockedUsers(ids, users, true); @@ -872,8 +817,12 @@ public class MessagesStorage { cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.mid, m.ttl FROM messages as m INNER JOIN randoms as r ON m.mid = r.mid WHERE r.random_id IN (%s)", ids)); } while (cursor.next()) { + int ttl = cursor.intValue(1); + if (ttl <= 0) { + continue; + } int mid = cursor.intValue(0); - int date = Math.min(readTime, time) + cursor.intValue(1); + int date = Math.min(readTime, time) + ttl; minDate = Math.min(minDate, date); ArrayList arr = messages.get(date); if (arr == null) { @@ -1126,19 +1075,7 @@ public class MessagesStorage { } } if (usersToLoad.length() != 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad.toString())); - while (cursor.next()) { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - loadedUsers.add(user); - if (user.status != null) { - user.status.expires = cursor.intValue(1); - } - } - buffersStorage.reuseFreeBuffer(data); - } - cursor.dispose(); + getUsersInternal(usersToLoad.toString(), loadedUsers); } if (modified) { updateChatInfo(chat_id, info, false); @@ -1225,7 +1162,18 @@ public class MessagesStorage { SQLiteCursor cursor = database.queryFinalized("SELECT u.data, u.status, u.name FROM users as u INNER JOIN contacts as c ON u.uid = c.uid"); while (cursor.next()) { String name = cursor.stringValue(2); + String username = null; + int usernamePos = name.lastIndexOf(";;;"); + if (usernamePos != -1) { + username = name.substring(usernamePos + 3); + } + int found = 0; if (name.startsWith(q) || name.contains(" " + q)) { + found = 1; + } else if (username != null && username.startsWith(q)) { + found = 2; + } + if (found != 0) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); @@ -1233,7 +1181,11 @@ public class MessagesStorage { if (user.status != null) { user.status.expires = cursor.intValue(1); } - resultArrayNames.add(Utilities.generateSearchName(user.first_name, user.last_name, q)); + if (found == 1) { + resultArrayNames.add(Utilities.generateSearchName(user.first_name, user.last_name, q)); + } else { + resultArrayNames.add(Utilities.generateSearchName("@" + user.username, null, "@" + q)); + } resultArray.add(user); } } @@ -1246,7 +1198,20 @@ public class MessagesStorage { cursor = database.queryFinalized("SELECT q.data, u.name, q.user, q.g, q.authkey, q.ttl, u.data, u.status, q.layer, q.seq_in, q.seq_out FROM enc_chats as q INNER JOIN dialogs as d ON (q.uid << 32) = d.did INNER JOIN users as u ON q.user = u.uid"); while (cursor.next()) { String name = cursor.stringValue(1); + + String username = null; + int usernamePos = name.lastIndexOf(";;;"); + if (usernamePos != -1) { + username = name.substring(usernamePos + 2); + } + int found = 0; if (name.startsWith(q) || name.contains(" " + q)) { + found = 1; + } else if (username != null && username.startsWith(q)) { + found = 2; + } + + if (found != 0) { ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); ByteBufferDesc data2 = buffersStorage.getFreeBuffer(cursor.byteArrayLength(6)); if (data != null && cursor.byteBufferValue(0, data.buffer) != 0 && cursor.byteBufferValue(6, data2.buffer) != 0) { @@ -1263,7 +1228,11 @@ public class MessagesStorage { if (user.status != null) { user.status.expires = cursor.intValue(7); } - resultArrayNames.add(Html.fromHtml("" + ContactsController.formatName(user.first_name, user.last_name) + "")); + if (found == 1) { + resultArrayNames.add(Html.fromHtml("" + ContactsController.formatName(user.first_name, user.last_name) + "")); + } else { + resultArrayNames.add(Utilities.generateSearchName("@" + user.username, null, "@" + q)); + } resultArray.add(chat); encUsers.add(user); } @@ -1473,19 +1442,7 @@ public class MessagesStorage { cursor.dispose(); if (uids.length() != 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", uids.toString())); - while (cursor.next()) { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - users.add(user); - if (user.status != null) { - user.status.expires = cursor.intValue(1); - } - } - buffersStorage.reuseFreeBuffer(data); - } - cursor.dispose(); + getUsersInternal(uids.toString(), users); } } catch (Exception e) { contacts.clear(); @@ -1597,20 +1554,7 @@ public class MessagesStorage { } } if (usersToLoad.length() != 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad.toString())); - while (cursor.next()) { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - loadedUsers.add(user.id); - if (user.status != null) { - user.status.expires = cursor.intValue(1); - } - res.users.add(user); - } - buffersStorage.reuseFreeBuffer(data); - } - cursor.dispose(); + getUsersInternal(usersToLoad.toString(), res.users); } } catch (Exception e) { res.messages.clear(); @@ -1737,45 +1681,11 @@ public class MessagesStorage { if (!encryptedChatIds.isEmpty()) { - String stringToLoad = TextUtils.join(",", encryptedChatIds); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer, seq_in, seq_out FROM enc_chats WHERE uid IN(%s)", stringToLoad)); - while (cursor.next()) { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - encryptedChats.add(chat); - chat.user_id = cursor.intValue(1); - if (!userIds.contains(chat.user_id)) { - userIds.add(chat.user_id); - } - chat.a_or_b = cursor.byteArrayValue(2); - chat.auth_key = cursor.byteArrayValue(3); - chat.ttl = cursor.intValue(4); - chat.layer = cursor.intValue(5); - chat.seq_in = cursor.intValue(6); - chat.seq_out = cursor.intValue(7); - } - buffersStorage.reuseFreeBuffer(data); - } - cursor.dispose(); + getEncryptedChatsInternal(TextUtils.join(",", encryptedChatIds), encryptedChats, userIds); } - if (!userIds.isEmpty()) { - String stringToLoad = TextUtils.join(",", userIds); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", stringToLoad)); - while (cursor.next()) { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - TLRPC.User user = (TLRPC.User) TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - if (user.status != null) { - user.status.expires = cursor.intValue(1); - } - users.add(user); - } - buffersStorage.reuseFreeBuffer(data); - } - cursor.dispose(); + getUsersInternal(TextUtils.join(",", userIds), users); } if (!chatIds.isEmpty() || !broadcastIds.isEmpty()) { @@ -1792,16 +1702,7 @@ public class MessagesStorage { } stringToLoad.append(-cid); } - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid IN(%s)", stringToLoad.toString())); - while (cursor.next()) { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - TLRPC.Chat chat = (TLRPC.Chat) TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - chats.add(chat); - } - buffersStorage.reuseFreeBuffer(data); - } - cursor.dispose(); + getChatsInternal(stringToLoad.toString(), chats); } SendMessagesHelper.getInstance().processUnsentMessages(messages, users, chats, encryptedChats); @@ -2017,20 +1918,7 @@ public class MessagesStorage { } } if (usersToLoad.length() != 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad.toString())); - while (cursor.next()) { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - loadedUsers.add(user.id); - if (user.status != null) { - user.status.expires = cursor.intValue(1); - } - res.users.add(user); - } - buffersStorage.reuseFreeBuffer(data); - } - cursor.dispose(); + getUsersInternal(usersToLoad.toString(), res.users); } } catch (Exception e) { res.messages.clear(); @@ -2270,42 +2158,15 @@ public class MessagesStorage { @Override public void run() { try { - int userToLoad = 0; - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer, seq_in, seq_out FROM enc_chats WHERE uid = %d", chat_id)); - if (cursor.next()) { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - result.add(chat); - chat.user_id = cursor.intValue(1); - userToLoad = chat.user_id; - chat.a_or_b = cursor.byteArrayValue(2); - chat.auth_key = cursor.byteArrayValue(3); - chat.ttl = cursor.intValue(4); - chat.layer = cursor.intValue(5); - chat.seq_in = cursor.intValue(6); - chat.seq_out = cursor.intValue(7); - } - buffersStorage.reuseFreeBuffer(data); - } - cursor.dispose(); - if (userToLoad != 0) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid = %d", userToLoad)); - if (cursor.next()) { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - if (user.status != null) { - user.status.expires = cursor.intValue(1); - } - result.add(user); - } - buffersStorage.reuseFreeBuffer(data); - } - cursor.dispose(); - - if (result.size() != 2) { - result.clear(); + ArrayList usersToLoad = new ArrayList(); + ArrayList encryptedChats = new ArrayList(); + getEncryptedChatsInternal("" + chat_id, encryptedChats, usersToLoad); + if (!encryptedChats.isEmpty() && !usersToLoad.isEmpty()) { + ArrayList users = new ArrayList(); + getUsersInternal(TextUtils.join(",", usersToLoad), users); + if (!users.isEmpty()) { + result.add(encryptedChats.get(0)); + result.add(users.get(0)); } } } catch (Exception e) { @@ -2333,12 +2194,7 @@ public class MessagesStorage { chat.serializeToStream(data); state.bindInteger(1, chat.id); state.bindInteger(2, user.id); - if (user.first_name != null && user.last_name != null) { - String name = (user.first_name + " " + user.last_name).toLowerCase(); - state.bindString(3, name); - } else { - state.bindString(3, ""); - } + state.bindString(3, formatUserSearchName(user)); state.bindByteBuffer(4, data.buffer); if (chat.a_or_b != null) { data2.writeRaw(chat.a_or_b); @@ -2374,54 +2230,157 @@ public class MessagesStorage { }); } + private String formatUserSearchName(TLRPC.User user) { + StringBuilder str = new StringBuilder(""); + if (user.first_name != null && user.first_name.length() > 0) { + str.append(user.first_name); + } + if (user.last_name != null && user.last_name.length() > 0) { + if (str.length() > 0) { + str.append(" "); + } + str.append(user.last_name); + } + str.append(";;;"); + if (user.username != null && user.username.length() > 0) { + str.append(user.username); + } + return str.toString().toLowerCase(); + } + + private void putUsersInternal(ArrayList users) throws Exception { + if (users == null || users.isEmpty()) { + return; + } + SQLitePreparedStatement state = database.executeFast("REPLACE INTO users VALUES(?, ?, ?, ?)"); + for (TLRPC.User user : users) { + state.requery(); + ByteBufferDesc data = buffersStorage.getFreeBuffer(user.getObjectSize()); + user.serializeToStream(data); + state.bindInteger(1, user.id); + state.bindString(2, formatUserSearchName(user)); + if (user.status != null) { + state.bindInteger(3, user.status.expires); + } else { + state.bindInteger(3, 0); + } + state.bindByteBuffer(4, data.buffer); + state.step(); + buffersStorage.reuseFreeBuffer(data); + } + state.dispose(); + } + + private void putChatsInternal(ArrayList chats) throws Exception { + if (chats == null || chats.isEmpty()) { + return; + } + SQLitePreparedStatement state = database.executeFast("REPLACE INTO chats VALUES(?, ?, ?)"); + for (TLRPC.Chat chat : chats) { + state.requery(); + ByteBufferDesc data = buffersStorage.getFreeBuffer(chat.getObjectSize()); + chat.serializeToStream(data); + state.bindInteger(1, chat.id); + if (chat.title != null) { + String name = chat.title.toLowerCase(); + state.bindString(2, name); + } else { + state.bindString(2, ""); + } + state.bindByteBuffer(3, data.buffer); + state.step(); + buffersStorage.reuseFreeBuffer(data); + } + state.dispose(); + } + + private void getUsersInternal(String usersToLoad, ArrayList result) throws Exception { + if (usersToLoad == null || usersToLoad.length() == 0 || result == null) { + return; + } + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad)); + while (cursor.next()) { + try { + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { + TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); + if (user != null) { + if (user.status != null) { + user.status.expires = cursor.intValue(1); + } + result.add(user); + } + } + buffersStorage.reuseFreeBuffer(data); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + cursor.dispose(); + } + + private void getChatsInternal(String chatsToLoad, ArrayList result) throws Exception { + if (chatsToLoad == null || chatsToLoad.length() == 0 || result == null) { + return; + } + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid IN(%s)", chatsToLoad)); + while (cursor.next()) { + try { + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { + TLRPC.Chat chat = (TLRPC.Chat)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); + if (chat != null) { + result.add(chat); + } + } + buffersStorage.reuseFreeBuffer(data); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + cursor.dispose(); + } + + private void getEncryptedChatsInternal(String chatsToLoad, ArrayList result, ArrayList usersToLoad) throws Exception { + if (chatsToLoad == null || chatsToLoad.length() == 0 || result == null) { + return; + } + + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer, seq_in, seq_out FROM enc_chats WHERE uid IN(%s)", chatsToLoad)); + while (cursor.next()) { + try { + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { + TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); + if (chat != null) { + chat.user_id = cursor.intValue(1); + if (usersToLoad != null && !usersToLoad.contains(chat.user_id)) { + usersToLoad.add(chat.user_id); + } + chat.a_or_b = cursor.byteArrayValue(2); + chat.auth_key = cursor.byteArrayValue(3); + chat.ttl = cursor.intValue(4); + chat.layer = cursor.intValue(5); + chat.seq_in = cursor.intValue(6); + chat.seq_out = cursor.intValue(7); + result.add(chat); + } + } + buffersStorage.reuseFreeBuffer(data); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + cursor.dispose(); + } + private void putUsersAndChatsInternal(final ArrayList users, final ArrayList chats, final boolean withTransaction) { try { if (withTransaction) { database.beginTransaction(); } - if (users != null && !users.isEmpty()) { - SQLitePreparedStatement state = database.executeFast("REPLACE INTO users VALUES(?, ?, ?, ?)"); - for (TLRPC.User user : users) { - state.requery(); - ByteBufferDesc data = buffersStorage.getFreeBuffer(user.getObjectSize()); - user.serializeToStream(data); - state.bindInteger(1, user.id); - if (user.first_name != null && user.last_name != null) { - String name = (user.first_name + " " + user.last_name).toLowerCase(); - state.bindString(2, name); - } else { - state.bindString(2, ""); - } - if (user.status != null) { - state.bindInteger(3, user.status.expires); - } else { - state.bindInteger(3, 0); - } - state.bindByteBuffer(4, data.buffer); - state.step(); - buffersStorage.reuseFreeBuffer(data); - } - state.dispose(); - } - if (chats != null && !chats.isEmpty()) { - SQLitePreparedStatement state = database.executeFast("REPLACE INTO chats VALUES(?, ?, ?)"); - for (TLRPC.Chat chat : chats) { - state.requery(); - ByteBufferDesc data = buffersStorage.getFreeBuffer(chat.getObjectSize()); - chat.serializeToStream(data); - state.bindInteger(1, chat.id); - if (chat.title != null) { - String name = chat.title.toLowerCase(); - state.bindString(2, name); - } else { - state.bindString(2, ""); - } - state.bindByteBuffer(3, data.buffer); - state.step(); - buffersStorage.reuseFreeBuffer(data); - } - state.dispose(); - } + putUsersInternal(users); + putChatsInternal(chats); if (withTransaction) { database.commitTransaction(); } @@ -2999,16 +2958,10 @@ public class MessagesStorage { usersDict.put(user.id, user); } ArrayList loadedUsers = new ArrayList(); - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", ids.toString())); - while (cursor.next()) { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - loadedUsers.add(user); - if (user.status != null) { - user.status.expires = cursor.intValue(1); - } - TLRPC.User updateUser = usersDict.get(user.id); + getUsersInternal(ids.toString(), loadedUsers); + for (TLRPC.User user : loadedUsers) { + TLRPC.User updateUser = usersDict.get(user.id); + if (updateUser != null) { if (updateUser.first_name != null && updateUser.last_name != null) { user.first_name = updateUser.first_name; user.last_name = updateUser.last_name; @@ -3017,35 +2970,13 @@ public class MessagesStorage { user.photo = updateUser.photo; } } - buffersStorage.reuseFreeBuffer(data); } - cursor.dispose(); + if (!loadedUsers.isEmpty()) { if (withTransaction) { database.beginTransaction(); } - SQLitePreparedStatement state = database.executeFast("REPLACE INTO users VALUES(?, ?, ?, ?)"); - for (TLRPC.User user : loadedUsers) { - state.requery(); - ByteBufferDesc data = buffersStorage.getFreeBuffer(user.getObjectSize()); - user.serializeToStream(data); - state.bindInteger(1, user.id); - if (user.first_name != null && user.last_name != null) { - String name = (user.first_name + " " + user.last_name).toLowerCase(); - state.bindString(2, name); - } else { - state.bindString(2, ""); - } - if (user.status != null) { - state.bindInteger(3, user.status.expires); - } else { - state.bindInteger(3, 0); - } - state.bindByteBuffer(4, data.buffer); - state.step(); - buffersStorage.reuseFreeBuffer(data); - } - state.dispose(); + putUsersInternal(loadedUsers); if (withTransaction) { database.commitTransaction(); } @@ -3308,58 +3239,15 @@ public class MessagesStorage { cursor.dispose(); if (!encryptedToLoad.isEmpty()) { - String toLoad = TextUtils.join(",", encryptedToLoad); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer, seq_in, seq_out FROM enc_chats WHERE uid IN(%s)", toLoad)); - while (cursor.next()) { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - encryptedChats.add(chat); - chat.user_id = cursor.intValue(1); - if (!usersToLoad.contains(chat.user_id)) { - usersToLoad.add(chat.user_id); - } - chat.a_or_b = cursor.byteArrayValue(2); - chat.auth_key = cursor.byteArrayValue(3); - chat.ttl = cursor.intValue(4); - chat.layer = cursor.intValue(5); - chat.seq_in = cursor.intValue(6); - chat.seq_out = cursor.intValue(7); - } - buffersStorage.reuseFreeBuffer(data); - } - cursor.dispose(); + getEncryptedChatsInternal(TextUtils.join(",", encryptedToLoad), encryptedChats, usersToLoad); } if (!chatsToLoad.isEmpty()) { - String toLoad = TextUtils.join(",", chatsToLoad); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid IN(%s)", toLoad)); - while (cursor.next()) { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - TLRPC.Chat chat = (TLRPC.Chat)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - dialogs.chats.add(chat); - } - buffersStorage.reuseFreeBuffer(data); - } - cursor.dispose(); + getChatsInternal(TextUtils.join(",", chatsToLoad), dialogs.chats); } if (!usersToLoad.isEmpty()) { - String toLoad = TextUtils.join(",", usersToLoad); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", toLoad)); - while (cursor.next()) { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - if (user.status != null) { - user.status.expires = cursor.intValue(1); - } - dialogs.users.add(user); - } - buffersStorage.reuseFreeBuffer(data); - } - cursor.dispose(); + getUsersInternal(TextUtils.join(",", usersToLoad), dialogs.users); } if (!dialogs.dialogs.isEmpty() || !encryptedChats.isEmpty()) { @@ -3442,49 +3330,8 @@ public class MessagesStorage { state.dispose(); state2.dispose(); } - if (!messages.users.isEmpty()) { - SQLitePreparedStatement state = database.executeFast("REPLACE INTO users VALUES(?, ?, ?, ?)"); - for (TLRPC.User user : messages.users) { - state.requery(); - ByteBufferDesc data = buffersStorage.getFreeBuffer(user.getObjectSize()); - user.serializeToStream(data); - state.bindInteger(1, user.id); - if (user.first_name != null && user.last_name != null) { - String name = (user.first_name + " " + user.last_name).toLowerCase(); - state.bindString(2, name); - } else { - state.bindString(2, ""); - } - if (user.status != null) { - state.bindInteger(3, user.status.expires); - } else { - state.bindInteger(3, 0); - } - state.bindByteBuffer(4, data.buffer); - state.step(); - buffersStorage.reuseFreeBuffer(data); - } - state.dispose(); - } - if (!messages.chats.isEmpty()) { - SQLitePreparedStatement state = database.executeFast("REPLACE INTO chats VALUES(?, ?, ?)"); - for (TLRPC.Chat chat : messages.chats) { - state.requery(); - ByteBufferDesc data = buffersStorage.getFreeBuffer(chat.getObjectSize()); - chat.serializeToStream(data); - state.bindInteger(1, chat.id); - if (chat.title != null) { - String name = chat.title.toLowerCase(); - state.bindString(2, name); - } else { - state.bindString(2, ""); - } - state.bindByteBuffer(3, data.buffer); - state.step(); - buffersStorage.reuseFreeBuffer(data); - } - state.dispose(); - } + putUsersInternal(messages.users); + putChatsInternal(messages.chats); database.commitTransaction(); } catch (Exception e) { @@ -3567,76 +3414,15 @@ public class MessagesStorage { cursor.dispose(); if (!encryptedToLoad.isEmpty()) { - String toLoad = TextUtils.join(",", encryptedToLoad); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer, seq_in, seq_out FROM enc_chats WHERE uid IN(%s)", toLoad)); - while (cursor.next()) { - try { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - if (chat != null) { - encryptedChats.add(chat); - chat.user_id = cursor.intValue(1); - if (!usersToLoad.contains(chat.user_id)) { - usersToLoad.add(chat.user_id); - } - chat.a_or_b = cursor.byteArrayValue(2); - chat.auth_key = cursor.byteArrayValue(3); - chat.ttl = cursor.intValue(4); - chat.layer = cursor.intValue(5); - chat.seq_in = cursor.intValue(6); - chat.seq_out = cursor.intValue(7); - } - } - buffersStorage.reuseFreeBuffer(data); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - cursor.dispose(); + getEncryptedChatsInternal(TextUtils.join(",", encryptedToLoad), encryptedChats, usersToLoad); } if (!chatsToLoad.isEmpty()) { - String toLoad = TextUtils.join(",", chatsToLoad); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid IN(%s)", toLoad)); - while (cursor.next()) { - try { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - TLRPC.Chat chat = (TLRPC.Chat)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - if (chat != null) { - dialogs.chats.add(chat); - } - } - buffersStorage.reuseFreeBuffer(data); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - cursor.dispose(); + getChatsInternal(TextUtils.join(",", chatsToLoad), dialogs.chats); } if (!usersToLoad.isEmpty()) { - String toLoad = TextUtils.join(",", usersToLoad); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", toLoad)); - while (cursor.next()) { - try { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - if (user != null) { - if (user.status != null) { - user.status.expires = cursor.intValue(1); - } - dialogs.users.add(user); - } - } - buffersStorage.reuseFreeBuffer(data); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - cursor.dispose(); + getUsersInternal(TextUtils.join(",", usersToLoad), dialogs.users); } MessagesController.getInstance().processLoadedDialogs(dialogs, encryptedChats, offset, serverOffset, count, true, false); } catch (Exception e) { @@ -3725,50 +3511,8 @@ public class MessagesStorage { state4.dispose(); } - if (!dialogs.users.isEmpty()) { - SQLitePreparedStatement state = database.executeFast("REPLACE INTO users VALUES(?, ?, ?, ?)"); - for (TLRPC.User user : dialogs.users) { - state.requery(); - ByteBufferDesc data = buffersStorage.getFreeBuffer(user.getObjectSize()); - user.serializeToStream(data); - state.bindInteger(1, user.id); - if (user.first_name != null && user.last_name != null) { - String name = (user.first_name + " " + user.last_name).toLowerCase(); - state.bindString(2, name); - } else { - state.bindString(2, ""); - } - if (user.status != null) { - state.bindInteger(3, user.status.expires); - } else { - state.bindInteger(3, 0); - } - state.bindByteBuffer(4, data.buffer); - state.step(); - buffersStorage.reuseFreeBuffer(data); - } - state.dispose(); - } - - if (!dialogs.chats.isEmpty()) { - SQLitePreparedStatement state = database.executeFast("REPLACE INTO chats VALUES(?, ?, ?)"); - for (TLRPC.Chat chat : dialogs.chats) { - state.requery(); - ByteBufferDesc data = buffersStorage.getFreeBuffer(chat.getObjectSize()); - chat.serializeToStream(data); - state.bindInteger(1, chat.id); - if (chat.title != null) { - String name = chat.title.toLowerCase(); - state.bindString(2, name); - } else { - state.bindString(2, ""); - } - state.bindByteBuffer(3, data.buffer); - state.step(); - buffersStorage.reuseFreeBuffer(data); - } - state.dispose(); - } + putUsersInternal(dialogs.users); + putChatsInternal(dialogs.chats); database.commitTransaction(); @@ -3783,56 +3527,23 @@ public class MessagesStorage { public TLRPC.User getUser(final int user_id) { TLRPC.User user = null; try { - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid = %d", user_id)); - if (cursor.next()) { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - user = (TLRPC.User) TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - if (user != null) { - if (user.status != null) { - user.status.expires = cursor.intValue(1); - } - } - } - buffersStorage.reuseFreeBuffer(data); + ArrayList users = new ArrayList(); + getUsersInternal("" + user_id, users); + if (!users.isEmpty()) { + user = users.get(0); } - cursor.dispose(); } catch (Exception e) { FileLog.e("tmessages", e); } return user; } - public ArrayList getUsers(final ArrayList uids, final boolean[] error) { + public ArrayList getUsers(final ArrayList uids) { ArrayList users = new ArrayList(); try { - String uidsStr = TextUtils.join(",", uids); - - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN (%s)", uidsStr)); - while (cursor.next()) { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - TLRPC.User user = (TLRPC.User) TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - if (user != null) { - if (user.status != null) { - user.status.expires = cursor.intValue(1); - } - users.add(user); - } else { - error[0] = true; - buffersStorage.reuseFreeBuffer(data); - break; - } - } else { - error[0] = true; - buffersStorage.reuseFreeBuffer(data); - break; - } - buffersStorage.reuseFreeBuffer(data); - } - cursor.dispose(); + getUsersInternal(TextUtils.join(",", uids), users); } catch (Exception e) { - error[0] = true; + users.clear(); FileLog.e("tmessages", e); } return users; @@ -3841,15 +3552,11 @@ public class MessagesStorage { public TLRPC.Chat getChat(final int chat_id) { TLRPC.Chat chat = null; try { - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid = %d", chat_id)); - if (cursor.next()) { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - chat = (TLRPC.Chat) TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - } - buffersStorage.reuseFreeBuffer(data); + ArrayList chats = new ArrayList(); + getChatsInternal("" + chat_id, chats); + if (!chats.isEmpty()) { + chat = chats.get(0); } - cursor.dispose(); } catch (Exception e) { FileLog.e("tmessages", e); } @@ -3859,24 +3566,11 @@ public class MessagesStorage { public TLRPC.EncryptedChat getEncryptedChat(final int chat_id) { TLRPC.EncryptedChat chat = null; try { - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer, seq_in, seq_out FROM enc_chats WHERE uid = %d", chat_id)); - if (cursor.next()) { - ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { - chat = (TLRPC.EncryptedChat) TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - if (chat != null) { - chat.user_id = cursor.intValue(1); - chat.a_or_b = cursor.byteArrayValue(2); - chat.auth_key = cursor.byteArrayValue(3); - chat.ttl = cursor.intValue(4); - chat.layer = cursor.intValue(5); - chat.seq_in = cursor.intValue(6); - chat.seq_out = cursor.intValue(7); - } - } - buffersStorage.reuseFreeBuffer(data); + ArrayList encryptedChats = new ArrayList(); + getEncryptedChatsInternal("" + chat_id, encryptedChats, null); + if (!encryptedChats.isEmpty()) { + chat = encryptedChats.get(0); } - cursor.dispose(); } catch (Exception e) { FileLog.e("tmessages", e); } diff --git a/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java index 27cdd036..770a38c5 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/android/SendMessagesHelper.java @@ -626,10 +626,12 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter newMsg.to_id.user_id = encryptedChat.participant_id; } newMsg.ttl = encryptedChat.ttl; - if (newMsg.media instanceof TLRPC.TL_messageMediaAudio) { - newMsg.ttl = Math.max(encryptedChat.ttl, newMsg.media.audio.duration + 1); - } else if (newMsg.media instanceof TLRPC.TL_messageMediaVideo) { - newMsg.ttl = Math.max(encryptedChat.ttl, newMsg.media.video.duration + 1); + if (newMsg.ttl != 0) { + if (newMsg.media instanceof TLRPC.TL_messageMediaAudio) { + newMsg.ttl = Math.max(encryptedChat.ttl, newMsg.media.audio.duration + 1); + } else if (newMsg.media instanceof TLRPC.TL_messageMediaVideo) { + newMsg.ttl = Math.max(encryptedChat.ttl, newMsg.media.video.duration + 1); + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivitySearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivitySearchAdapter.java index cab7b647..d58d86bd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivitySearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivitySearchAdapter.java @@ -99,12 +99,25 @@ public class ContactsActivitySearchAdapter extends BaseContactsSearchAdapter { for (TLRPC.TL_contact contact : contactsCopy) { TLRPC.User user = MessagesController.getInstance().getUser(contact.user_id); + if (user.id == UserConfig.getClientUserId()) { + continue; + } + String name = ContactsController.formatName(user.first_name, user.last_name).toLowerCase(); + + int found = 0; if (name.startsWith(q) || name.contains(" " + q)) { - if (user.id == UserConfig.getClientUserId()) { - continue; + found = 1; + } else if (user.username != null && user.username.startsWith(q)) { + found = 2; + } + + if (found != 0) { + if (found == 1) { + resultArrayNames.add(Utilities.generateSearchName(user.first_name, user.last_name, q)); + } else { + resultArrayNames.add(Utilities.generateSearchName("@" + user.username, null, "@" + q)); } - resultArrayNames.add(Utilities.generateSearchName(user.first_name, user.last_name, q)); resultArray.add(user); } } @@ -197,7 +210,16 @@ public class ContactsActivitySearchAdapter extends BaseContactsSearchAdapter { TLRPC.User user = getItem(i); if (user != null) { CharSequence username = null; - if (i > searchResult.size() && user.username != null) { + CharSequence name = null; + if (i < searchResult.size()) { + name = searchResultNames.get(i); + if (name != null && user != null && user.username != null && user.username.length() > 0) { + if (name.toString().startsWith("@" + user.username)) { + username = name; + name = null; + } + } + } else if (i > searchResult.size() && user.username != null) { try { username = Html.fromHtml(String.format("@%s%s", user.username.substring(0, lastFoundUsername.length()), user.username.substring(lastFoundUsername.length()))); } catch (Exception e) { @@ -206,7 +228,7 @@ public class ContactsActivitySearchAdapter extends BaseContactsSearchAdapter { } } - ((ChatOrUserCell) view).setData(user, null, null, i < searchResult.size() ? searchResultNames.get(i) : null, username); + ((ChatOrUserCell) view).setData(user, null, null, name, username); if (ignoreUsers != null) { if (ignoreUsers.containsKey(user.id)) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index e5918f4b..c4af50a4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -1040,7 +1040,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private boolean sendSecretMessageRead(MessageObject messageObject) { - if (messageObject == null || messageObject.isOut() || !messageObject.isSecretMedia() || messageObject.messageOwner.destroyTime != 0) { + if (messageObject == null || messageObject.isOut() || !messageObject.isSecretMedia() || messageObject.messageOwner.destroyTime != 0 || messageObject.messageOwner.ttl <= 0) { return false; } MessagesController.getInstance().markMessageAsRead(dialog_id, messageObject.messageOwner.random_id, messageObject.messageOwner.ttl); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileActivity.java index dc7dd128..f8f556b4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileActivity.java @@ -477,7 +477,7 @@ public class ChatProfileActivity extends BaseFragment implements NotificationCen args.putBoolean("destroyAfterSelect", true); args.putBoolean("usersAsSections", true); args.putBoolean("returnAsResult", true); - args.putBoolean("allowUsernameSearch", false); + //args.putBoolean("allowUsernameSearch", false); if (chat_id > 0) { args.putString("selectAlertString", LocaleController.getString("AddToTheGroup", R.string.AddToTheGroup)); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java index 972f87c4..331dc705 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java @@ -82,11 +82,10 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati if (!usersToLoad.isEmpty()) { final Semaphore semaphore = new Semaphore(0); final ArrayList users = new ArrayList(); - final boolean[] error = new boolean[1]; MessagesStorage.getInstance().storageQueue.postRunnable(new Runnable() { @Override public void run() { - users.addAll(MessagesStorage.getInstance().getUsers(usersToLoad, error)); + users.addAll(MessagesStorage.getInstance().getUsers(usersToLoad)); semaphore.release(); } }); @@ -95,7 +94,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati } catch (Exception e) { FileLog.e("tmessages", e); } - if (error[0]) { + if (usersToLoad.size() != users.size()) { return false; } if (!users.isEmpty()) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MessagesActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/MessagesActivity.java index 6f2b8ec6..477a519a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/MessagesActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/MessagesActivity.java @@ -775,17 +775,19 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter @Override public View getView(int i, View view, ViewGroup viewGroup) { - if (searching && searchWas) { - if (i == searchResult.size()) { - if (view == null) { - view = new SettingsSectionLayout(mContext); - ((SettingsSectionLayout) view).setText(LocaleController.getString("GlobalSearch", R.string.GlobalSearch)); - view.setPadding(AndroidUtilities.dp(11), 0, AndroidUtilities.dp(11), 0); - } - } else { - if (view == null) { - view = new ChatOrUserCell(mContext); - } + int type = getItemViewType(i); + + if (type == 3) { + if (view == null) { + view = new SettingsSectionLayout(mContext); + ((SettingsSectionLayout) view).setText(LocaleController.getString("GlobalSearch", R.string.GlobalSearch)); + view.setPadding(AndroidUtilities.dp(11), 0, AndroidUtilities.dp(11), 0); + } + } else if (type == 2) { + if (view == null) { + view = new ChatOrUserCell(mContext); + } + if (searching && searchWas) { TLRPC.User user = null; TLRPC.Chat chat = null; TLRPC.EncryptedChat encryptedChat = null; @@ -795,7 +797,7 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter if (obj instanceof TLRPC.User) { user = MessagesController.getInstance().getUser(((TLRPC.User) obj).id); if (user == null) { - user = (TLRPC.User)obj; + user = (TLRPC.User) obj; } } else if (obj instanceof TLRPC.Chat) { chat = MessagesController.getInstance().getChat(((TLRPC.Chat) obj).id); @@ -805,7 +807,16 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter } CharSequence username = null; - if (i > searchResult.size() && user != null && user.username != null) { + CharSequence name = null; + if (i < searchResult.size()) { + name = searchResultNames.get(i); + if (name != null && user != null && user.username != null && user.username.length() > 0) { + if (name.toString().startsWith("@" + user.username)) { + username = name; + name = null; + } + } + } else if (i > searchResult.size() && user != null && user.username != null) { try { username = Html.fromHtml(String.format("@%s%s", user.username.substring(0, lastFoundUsername.length()), user.username.substring(lastFoundUsername.length()))); } catch (Exception e) { @@ -814,36 +825,31 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter } } - ((ChatOrUserCell) view).setData(user, chat, encryptedChat, i < searchResult.size() ? searchResultNames.get(i) : null, username); + ((ChatOrUserCell) view).setData(user, chat, encryptedChat, name, username); } - - return view; - } - int type = getItemViewType(i); - if (type == 1) { + } else if (type == 1) { if (view == null) { LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = li.inflate(R.layout.loading_more_layout, viewGroup, false); } - return view; - } - - if (view == null) { - view = new DialogCell(mContext); - } - ((DialogCell) view).useSeparator = (i != getCount() - 1); - if (serverOnly) { - ((DialogCell)view).setDialog(MessagesController.getInstance().dialogsServerOnly.get(i)); - } else { - TLRPC.TL_dialog dialog = MessagesController.getInstance().dialogs.get(i); - if (AndroidUtilities.isTablet()) { - if (dialog.id == openedDialogId) { - view.setBackgroundColor(0x0f000000); - } else { - view.setBackgroundColor(0); - } + } else if (type == 0) { + if (view == null) { + view = new DialogCell(mContext); + } + ((DialogCell) view).useSeparator = (i != getCount() - 1); + if (serverOnly) { + ((DialogCell) view).setDialog(MessagesController.getInstance().dialogsServerOnly.get(i)); + } else { + TLRPC.TL_dialog dialog = MessagesController.getInstance().dialogs.get(i); + if (AndroidUtilities.isTablet()) { + if (dialog.id == openedDialogId) { + view.setBackgroundColor(0x0f000000); + } else { + view.setBackgroundColor(0); + } + } + ((DialogCell) view).setDialog(dialog); } - ((DialogCell)view).setDialog(dialog); } return view; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index a0a34961..c566a2ba 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -1173,6 +1173,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat menuItem.hideSubItem(gallery_menu_save); shareButton.setVisibility(View.GONE); } else { + menuItem.showSubItem(gallery_menu_save); shareButton.setVisibility(View.VISIBLE); } setImageIndex(0, true); @@ -1215,6 +1216,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat menuItem.hideSubItem(gallery_menu_save); shareButton.setVisibility(View.GONE); } else { + menuItem.showSubItem(gallery_menu_save); shareButton.setVisibility(View.VISIBLE); } opennedFromMedia = true; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java index d5fdfb34..3f893ca7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeUsernameActivity.java @@ -194,6 +194,9 @@ public class SettingsChangeUsernameActivity extends BaseFragment { } private void showErrorAlert(String error) { + if (getParentActivity() == null) { + return; + } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); if (error.equals("USERNAME_INVALID")) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/VideoEditorActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/VideoEditorActivity.java index 6a9c7027..18ed3fd9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/VideoEditorActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/VideoEditorActivity.java @@ -457,11 +457,17 @@ public class VideoEditorActivity extends BaseFragment implements TextureView.Sur } private void onPlayComplete() { - playButton.setImageResource(R.drawable.video_play); - videoSeekBarView.setProgress(videoTimelineView.getLeftProgress()); + if (playButton != null) { + playButton.setImageResource(R.drawable.video_play); + } + if (videoSeekBarView != null && videoTimelineView != null) { + videoSeekBarView.setProgress(videoTimelineView.getLeftProgress()); + } try { if (videoPlayer != null) { - videoPlayer.seekTo((int) (videoTimelineView.getLeftProgress() * videoDuration)); + if (videoTimelineView != null) { + videoPlayer.seekTo((int) (videoTimelineView.getLeftProgress() * videoDuration)); + } } } catch (Exception e) { FileLog.e("tmessages", e); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/ChatActivityEnterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/ChatActivityEnterView.java index 96c92a17..5dbd1fdb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/ChatActivityEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/ChatActivityEnterView.java @@ -597,24 +597,22 @@ public class ChatActivityEnterView implements NotificationCenter.NotificationCen messsageEditText.dispatchKeyEvent(new KeyEvent(0, 67)); } - public void onEmojiSelected(String paramAnonymousString) { + public void onEmojiSelected(String symbol) { int i = messsageEditText.getSelectionEnd(); - CharSequence localCharSequence = Emoji.replaceEmoji(paramAnonymousString, messsageEditText.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20)); - messsageEditText.setText(messsageEditText.getText().insert(i, localCharSequence)); - int j = i + localCharSequence.length(); - messsageEditText.setSelection(j, j); + if (i < 0) { + i = 0; + } + try { + CharSequence localCharSequence = Emoji.replaceEmoji(symbol, messsageEditText.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20)); + messsageEditText.setText(messsageEditText.getText().insert(i, localCharSequence)); + int j = i + localCharSequence.length(); + messsageEditText.setSelection(j, j); + } catch (Exception e) { + FileLog.e("tmessages", e); + } } }); emojiPopup = new PopupWindow(emojiView); - - /*try { - Method method = emojiPopup.getClass().getMethod("setWindowLayoutType", int.class); - if (method != null) { - method.invoke(emojiPopup, WindowManager.LayoutParams.LAST_SUB_WINDOW); - } - } catch (Exception e) { - //don't promt - }*/ } public void setDelegate(ChatActivityEnterViewDelegate delegate) { diff --git a/TMessagesProj/src/main/res/anim/scale_in.xml b/TMessagesProj/src/main/res/anim/scale_in.xml index 406fd345..a0aa6293 100644 --- a/TMessagesProj/src/main/res/anim/scale_in.xml +++ b/TMessagesProj/src/main/res/anim/scale_in.xml @@ -20,12 +20,12 @@ android:fromAlpha="0.0" android:toAlpha="1.0" android:interpolator="@anim/decelerate_cubic" - android:duration="220"/> + android:duration="150"/> + android:duration="150"/> \ No newline at end of file diff --git a/TMessagesProj/src/main/res/anim/scale_out.xml b/TMessagesProj/src/main/res/anim/scale_out.xml index 17bd0e7c..11135b97 100644 --- a/TMessagesProj/src/main/res/anim/scale_out.xml +++ b/TMessagesProj/src/main/res/anim/scale_out.xml @@ -20,7 +20,7 @@ android:fromAlpha="1.0" android:toAlpha="0.0" android:interpolator="@anim/decelerate_cubic" - android:duration="220"/> + android:duration="150"/> + android:duration="150"/> \ No newline at end of file